收藏 分享(赏)

让javascript跑得更快.doc

上传人:ysd1539 文档编号:6103024 上传时间:2019-03-27 格式:DOC 页数:10 大小:70KB
下载 相关 举报
让javascript跑得更快.doc_第1页
第1页 / 共10页
让javascript跑得更快.doc_第2页
第2页 / 共10页
让javascript跑得更快.doc_第3页
第3页 / 共10页
让javascript跑得更快.doc_第4页
第4页 / 共10页
让javascript跑得更快.doc_第5页
第5页 / 共10页
点击查看更多>>
资源描述

1、让 javascript 跑得更快下一代 web 应用让 javascript 和 css 得堪大用。我们会告诉你怎样使这些应用又快又灵。建立了号称“Web 2.0” 的应用,也实现了富内容(rich content)和交互,我们期待着 css 和 javascript 扮演更加重要的角色。为使应用干净利落,我们需要完善那些渲染页面的文件,优化其大小和形态,以确保提供最好的用户体验在实践中,这就意味着一种结合:使内容尽可能小、下载尽可能快,同时避免对未改动资源不必要的重新获取。由于 css 和 js 文件的形态,情况有点复杂。跟图片相比,其源代码很有可能频繁改动。而一旦改动,就需要客户端重新下

2、载,使本地缓存无效(保存在其他缓存里的版本也是如此) 。在这篇文章里,我们将着重探讨怎样使用户体验最快:包括初始页面的下载,随后页面的下载,以及随着应用渐进、内容变化而进行的资源下载。我始终坚信这一点:对开发者来说,应该尽可能让事情变得简单。所以我们青睐于那些能让系统自动处理优化难题的方法。只需少许工作量,我们就能建立一举多得的环境:它使开发变得简单,有极佳的终端性能,也不会改变现有的工作方式。好大一沱老的思路是,为优化性能,可以把多个 css 和 js 文件合并成极少数大文件。跟十个5k 的 js 文件相比,合并成一个50k 的文件更好。虽然代码总字节数没变,却避免了多个 HTTP 请求造成

3、的开销。每个请求都会在客户端和服务器两边有个建立和消除的过程,导致请求和响应 header 带来开销,还有服务器端更多的进程和线程资源消耗(可能还有为压缩内容耗费的 cpu 时间) 。(除了 HTTP 请求, )并发问题也很重要。默认情况下,在使用持久连接(persistent connections)时,ie和 firefox 在同一域名内只会同时下载两个资源(在 HTTP 1.1规格书中第8.1.4节的建议) (htmlor 注:可以通过修改注册表等方法改变这一默认配置) 。这就意味着,在我们等待下载2个 js 文件的同时,将无法下载图片资源。也就是说,这段时间内用户在页面上看不到图片。(

4、虽然合并文件能解决以上两个问题, )可是,这个方法有两个缺点。第一,把所有资源一起打包,将强制用户一次下载完所有资源。如果(不这么做,而是)把大块内容变成多个文件,下载开销就分散到了多个页面,同时缓解了会话中的速度压力(或完全避免了某些开销,这取决于用户选择的路径) 。如果为了随后页面下载得更快而让初始页面下载得很慢,我们将发现更多用户根本不会傻等着再去打开下一个页面。第二(这个影响更大,一直以来却没怎么被考虑过) ,在一个文件改动很频繁的环境里,如果采用单文件系统,那么每次改动文件都需要客户端把所有 css 和 js 重新下载一遍。假如我们的应用有个100k 的合成的js 大文件,任何微小的

5、改动都将强制客户端把这100k 再消化一遍。分解之道(看来合并成大文件不太合适。 )替代方案是个折中的办法:把 css 和 js 资源分散成多个子文件,按功能划分、保持文件个数尽可能少。这个方案也是有代价的,虽说开发时代码分散成逻辑块(logical chunks)能提高效率,可在下载时为提高性能还得合并文件。不过,只要给 build 系统(把开发代码变成产品代码的工具集,是为部署准备的)加点东西,就没什么问题了。对于有着不同开发和产品环境的应用来说,用些简单的技术可以让代码更好管理。在开发环境下,为使条理清晰,代码可以分散为多个逻辑部分(logical components) 。可以在 Sm

6、arty(一种 php 模板语言)里建立一个简单的函数来管理 javascript 的下载:n“;OUTPUT:(htmlor 注:wordpress 中会把“src”替换成不知所谓的字符,因此这里只有写成“SOURCE ”,使用代码时请注意替换,下同)就这么简单。然后我们就命令 build 过程(build process)去把确定的文件合并起来。这个例子里,合并的是 foo.js 和 bar.js,因为它们几乎总是一起下载。我们能让应用配置记住这一点,并修改模板函数去使用它。 (代码如下:)foobar.js,bar.js = foobar.js,baz.js = baz.js,);fun

7、ction smarty_insert_js($args)if ($GLOBALSconfigis_dev_site)$files = explode(, $argsfiles);else$files = array();foreach (explode(, $argsfiles) as $file)$files$GLOBALSconfigjs_source_map$file+;$files = array_keys($files);foreach ($files as $file)echo “n“;OUTPUT:模板里的源代码没必要为了分别适应开发和产品阶段而改动,它帮助我们在开发时保持文件

8、分散,发布成产品时把文件合并。想更进一步的话,可以把合并过程(merge process)写在 php 里,然后使用同一个(合并文件的)配置去执行。这样就只有一个配置文件,避免了同步问题。为了做的更加完美,我们还可以分析 css 和 js 文件在页面中同时出现的几率,以此决定合并哪些文件最合理(几乎总是同时出现的文件是合并的首选) 。对 css 来说,可以先建立一个主从关系的模型,它很有用。一个主样式表控制应用的所有样式表,多个子样式表控制不同的应用区域。采用这个方法,大多数页面只需下载两个 css 文件,而其中一个(指主样式表)在页面第一次请求时就会缓存。对没有太多 css 和 js 资源的

9、应用来说,这个方法在第一次请求时可能比单个大文件慢,但如果保持文件数量很少的话,你会发现其实它更快,因为每个页面的数据量更小。让人头疼的下载花销被分散到不同的应用区域,因此并发下载数保持在一个最小值,同时也使得页面的平均下载数据量很小。压缩谈到资源压缩,大多数人马上会想到 mod_gzip(但要当心,mod_gzip 实际上是个魔鬼,至少能让人做恶梦) 。它的原理很简单:浏览器请求资源时,会发送一个 header 表明自己能接受的内容编码。就像这样:;close F;$data = s!/*(.*?)*/!g; # 去掉注释$data = s!s+! !g; # 压缩空格$data = s!

10、!n!g; # 在结束大括号后添加换行$data = s!n$!; # 删除最后一个换行$data = s! ! !g; # 去除开始大括号后的空格$data = s!; !g; # 去除结束大括号前的空格 print $data;然后,就可以把单个的 css 文件传给脚本去压缩了。命令如下:press.css 做完这些简单的纯文本优化工作后,我们就能减少数据传输量多达50%了(这个量取决于你的代码格式,可能更多) 。这带来了更快的用户体验。不过我们真正想做的是,尽可能避免用户请求的发生除非确实有必要。这下 HTTP 缓存知识派上用场了。缓存是好东西当用户代理(如浏览器)向服务器请求一个资源时

11、,第一次请求过后它就会缓存服务器的响应,以避免重复之后的相同请求。缓存时间的长短取决于两个因素:代理的配置和服务器的缓存控制 header。所有浏览器都有不同的配置选项和处理方式,但大多数都会把一个资源至少缓存到会话结束(除非被明确告知) 。为了不让浏览器缓存改动频繁的页面,你很可能已经发送过 header 不缓存动态内容。在 php 中,以下两行命令可以做到:或标记向服务器发送一个请求,说明哪个页面要加载这些文件。这时候就可以用服务器的响应来通知客户端这些文件有了改动。有点含糊,说得再详细点就是:如果改变 css 和 js 文件内容的同时,也改变它们的文件名,就可以告诉客户端对 url全都永

12、久缓存因为每个 url 都是唯一的。假如能确定一个资源永不更改,我们就可以发出一些霸气十足的缓存 header(htmlor 注:这句也很有气势吧) 。在 php 里,两行就好:/images/foo.gif/css/main.v1.27.css - /css/main.css/javascript/md5.v6.js - /javascript/md5.js 使用这条规则,就可以做到不改变文件路径而更改 url(因为版本号变了) 。由于 url 变了,浏览器就认为它是另一个资源(会重新下载) 。想更进一步的话,可以把我们之前说的脚本编组函数结合起来,根据需要生成一个带有版本号的标记列表。说到

13、这里,你可能会问我,为什么不在 url 结尾加一个查询字符串(query string)呢(如/css/main.css?v=4)?根据 HTTP 缓存规格书所说,用户代理对含有查询字符串的 url 永不缓存。虽然 ie 跟 firefox 忽略了这点,opera 和 safari 却没有为了确保所有浏览器都缓存你的资源,还是不要在 url 里用查询字符串的好。现在不移动文件就能更改 url 了,如果能让 url 自动更新就更好了。在小型的产品环境下(如果有大型的产品环境,就是开发环境了) ,使用模板功能可以很轻易的实现这点。这里用的是 smarty,用其他模板引擎也行。PHP:functio

14、n smarty_version($args)$stat = stat($GLOBALSconfigsite_root.$argssrc);$version = $statmtime;echo preg_replace(!.(a-z+?)$!, “.v$version.$1“, $argssrc);OUTPUT:对每个链接到的资源文件,我们得到它在磁盘上的路径,检查它的 mtime(文件最后修改的日期和时间) ,然后把这个时间当作版本号插入到 url 中。对于低流量的站点(它们的 stat 操作开销不大)或者开发环境来说,这个方案不错,但对于高容量的环境就不适用了因为每次 stat 操作都要磁

15、盘读取(导致服务器负载升高) 。解决方案相当简单。在大型系统中每个资源都已经有了一个版本号,就是版本控制的修订号(你们应该使用了版本控制,对吧?) 。当我们建立站点准备部署的时候,可以轻易的查到每个文件的修订号,写在一个静态配置文件里。2.1,/css/main.css = 1.27,/javascript/md5.js = 6.1.4,); 当我们发布产品时,可以修改模板函数来使用版本号。?php function smarty_version($args)if ($GLOBALSconfigis_dev_site)$stat = stat($GLOBALSconfigsite_root.$

16、argssrc);$version = $statmtime;else$version = $GLOBALSconfigresource_versions$argssrc;echo preg_replace(!.(a-z+?)$!, “.v$version.$1“, $argssrc); 就这样,不需要改文件名,也不需要记住改了哪些文件当文件有新版本发布时它的 url 就会自动更新有意思吧?我们就快搞定了。只欠东风之前谈到为静态文件发送超长周期(very-long-period)的缓存 header 时曾说过,如果不用 php 输出,就不能轻易的发送缓存 header。很显然,有两个办法可以解

17、决:用 php 输出,或者让 apache 来做。php 出马,手到擒来。我们要做的仅仅是改变 rewrite 规则,把静态文件指向 php 脚本,用 php 在输出文件内容之前发送 header。?php Apache:RewriteRule /(.*.)v0-9.+.(css|js|gif|png|jpg)$ /redir.php?path=$1$2 LPHP:header(“Expires: “.gmdate(“D, d M Y H:i:s“, time()+315360000).“ GMT“);header(“Cache-Control: max-age=315360000“);# 忽

18、略带有“” 的路径if (preg_match(!, $_GETpath) go_404(); # 保证路径开头是确定的目录if (!preg_match(!(javascript|css|images)!, $_GETpath) go_404(); # 文件不存在?if (!file_exists($_GETpath) go_404(); # 发出一个文件类型 header$ext = array_pop(explode(., $_GETpath);switch ($ext)case css:header(“Content-type: text/css“);break;case js :he

19、ader(“Content-type: text/javascript“);break;case gif:header(“Content-type: image/gif“);break;case jpg:header(“Content-type: image/jpeg“);break;case png:header(“Content-type: image/png“);break;default:header(“Content-type: text/plain“);# 输出文件内容echo implode(, file($_GETpath);function go_404()header(“H

20、TTP/1.0 404 File not found“);exit; 这个方案有效,但并不出色。 (因为)跟 apache 相比,php 需要更多内存和执行时间。另外,我们还得小心防止可能由 path 参数传递伪造值引起的 exploits。为避免这些问题,应该用 apache 直接发送header。 rewrite 规则语句允许当规则匹配时设置环境变量(environment variable) ,当给定的环境变量设置后,Header 命令就可以添加 header。结合以下两条语句,我们就把 rewrite 规则和 header 设置绑定在了一起:?php RewriteEngine onR

21、ewriteRule /(.*.)v0-9.+.(css|js|gif|png|jpg)$ /$1$2 L,E=VERSIONED_FILE:1Header add “Expires“ “Mon, 28 Jul 2014 23:30:00 GMT“ env=VERSIONED_FILEHeader add “Cache-Control“ “max-age=315360000“ env=VERSIONED_FILE 考虑到 apache 的执行顺序,应该把 rewrite 规则加在主配置文件( httpd.conf)而不是目录配置文件(.htaccess)中。否则在环境变量设置之前,header

22、 行会先执行(就那没意义了) 。至于 header 行,则可以放在两文件任何一个当中,没什么区别。眼观六路( htmlor 注:多谢 tchaikov 告知 “skinning rabbits”的含义,但我不想翻的太正式,眼下的这个应该不算太离谱吧。 )通过结合使用以上技术,我们可以建立一个灵活的开发环境和一个快速又高性能的产品环境。当然,这离终极目标“速度” 还有一段距离。有许多更深层的技术(比如分离伺服静态内容,用多域名提升并发量等)值得我们关注,包括与我们谈到的方法(建立 apache 过滤器,修改资源 url,加上版本信息)殊途同归的其他路子。你可以留下评论,告诉我们那些你正在使用的卓有成效的技术和方法。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 网络科技 > Java

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报