Yahoo关于web前端性能优化的35条军规

时间:2022-01-26 05:58:28

最近公司社区网站刚上线,各种问题也是层出不穷。根据用户的反馈来看,用户体验和网站性能还有很大提升空间。

在web性能方面,根据Yahoo的调查,后台只占5%,而前端高达95%之多,其中有88%的东西是可以优化的。雅虎给出了优化网站加载速度的35条军规法则(原文:https://developer.yahoo.com/performance/rules.html),网上资源众多,今天来仔细整理一下,便于自己进一步加深理解。

1.Minimize HTTP Requests 尽量减少HTTP请求

80%~90%的终端响应时间,是花费在下载页面中的图片、css、script、flash等,减少这些元素的数量就能相应减少HTTP请求响应时间。适当简化页面的设计能减少页面元素的数量,以下技术能有效减少页面的HTTP请求:

合并文件:合并多个js文件和css文件。

CSS sprites :利用 CSS sprites 将页面中用到的背景、小图标拼合后,再使用css背景图像(background)和背景位置(background-position)来显示所需的图像部分。合并后的图像文件,占用的整体大小是差不多的,但能减少页面的HTTP请求次数。

CSS sprites 图标合并工具网站: http://www.csssprites.com/ ,可以自动将上传的多个小图标合并,生成一张png图片文件,并自动生成各小图标对应的background-position坐标样式。


2.Use a Content Delivery Network 使用CDN技术(内容分发网络)

简单地讲,通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的 cache服务器内,通过DNS负载均衡的技术,判断用户来源就近访问cache服务器取得所需的内容,杭州的用户访问近杭州服务器上的内容,北京的访问 近北京服务器上的内容。这样可以有效减少数据在网络上传输的时间,提高速度。更详细地内容大家可以参考百度百科上对于CDN的解释。Yahoo!把静态内容分布到CDN减少了用户影响时间20%或更多。


3.Add an Expires or a Cache-Control Header 设置头文件过期或者静态缓存

现在越来越多的图片,脚本,css,flash被嵌入到页面中,当我们访问他们的时候势必会做许多次的http请求。其实我们可以通过设置Expires header 来缓存这些文件。Expire其实就是通过header报文来指定特定类型的文件在览器中的缓存时间。大多数的图片,flash在发布后都是不需要经常修改的,做了缓存以后这样浏览器以后就不需要再从服务器下载这些文件而是而直接从缓存中读取,这样再次访问页面的速度会大大加快。

一个典型的HTTP 1.1协议返回的头信息:

HTTP/1.1 200 OK
Date: Fri, 30 Oct 1998 13:19:41 GMT
Server: Apache/1.3.3 (Unix)
Cache-Control: max-age=3600, must-revalidate
Expires: Fri, 30 Oct 1998 14:19:41 GMT
Last-Modified: Mon, 29 Jun 1998 02:28:12 GMT
ETag: “3e86-410-3596fbbc”
Content-Length: 1040
Content-Type: text/html

其中通过服务器端脚本设置Cache-Control和Expires可以完成。

也可以通过配置服务器本身完成,这些偶就不是很清楚了,呵呵。想了解跟多的朋友可以参考http://www.web-caching.com/

据我了解,目前阿里巴巴中文站的Expires过期时间是30天。不过期间也有过问题,特别是对于脚本过期时间的设置还是应该仔细考虑下,不然相应的脚本功能更新后客户端可能要过很长一段时间才能“感知”到这样的变化。所以,哪些应该缓存,哪些不该缓存还是应该仔细斟酌一番。

这项可以通过修改.htaccess文件来实现。


4.Gzip Components Gzip压缩

Gzip格式是一种很普遍的压缩技术,几乎所有的浏览器都有解压Gzip格式的能力,而且它可以压缩的比例非常大,一般压缩率为85%。

Gzip的思想就是把文件先在服务器端进行压缩,然后再传输。这样可以显著减少文件传输的大小。传输完毕后浏览器会 重新对压缩过的内容进行解压缩,并执行。目前的浏览器都能“良好”地支持 gzip。不仅浏览器可以识别,而且各大“爬虫”也同样可以识别,各位seoer可以放下心了。而且gzip的压缩比例非常大,一般压缩率为85%。雅虎特别强调, 所有的文本内容都应该被gzip压缩: html (php), js, css, xml, txt…


5.Put Stylesheets at the Top 把CSS放顶部

当我们研究雅虎网站的设置时可以发现,把CSS放在<head>标签中能让网页加载速度更快,这是因为让CSS在<head>能让页面先逐步渲染。

关注网站性能的前端工程师希望能逐步加载页面,而且,我们希望浏览器尽可能地显示所有内容,这对于内容很多的页面和网速很慢的用户特别重要。给用户一个可视化的反馈(比如进度指示器)的重要性,已经得到了研究和论证。HTML网页本身就是一个进度指示器!当浏览器逐步加载网页头、导航条、顶部logo……所有的显示元素都是用户等待网页加载时的可视化反馈,提高了用户体验。
把CSS放在网页文件底部会出现的问题是许多浏览器可能不再进行逐步渲染,包括IE。这些浏览器为了避免页面样式改变时重绘页面元素而阻止渲染。用户将看到一个被卡住不再显示的空白页面。
HTML规范中明确指出CSS要被包含在<head>:“与<a>标签不同,<link>只能出现在文档中的<head>里面,虽然它可能出现好多次。”空白屏幕或者由于因没有应用样式的内容引起的闪现或多或少有些冒险。最佳的解决办法是遵循HTML规范,在<head>中加载你的CSS。


6.Put Scripts at the Bottom 把JS放底部

将脚本放在页面最下面的目的有那么两点:

1、 因为防止script脚本的执行阻塞页面的下载。在页面loading的过程中,当浏览器读到js执行语句的时候一定会把它全部解释完毕后在会接下来读下 面的内容。不信你可以写一个js死循环看看页面下面的东西还会不会出来。(setTimeout 和 setInterval的执行有点类似于多线程,在相应的响应时间之前也会继续下面的内容渲染。)浏览器这么做的逻辑是因为js随时可能执 行 location.href或是其他可能完全中断此页面过程的函数,即如此,当然得等他执行完毕之后再加载咯。所以放在页面最后,可以有效减少页面可 视元素的加载时间。

2、脚本引起的第二个问题是它阻塞并行下载数量。HTTP/1.1规范建议浏览器每个主机的并行下载数不超过2个(IE只能为2个,其他浏览器如ff等都是默认设置为2个,不过新出的ie8可以达6个)。因此如果您把图像文件分布到多台机器的话,您可以达到超过2个的并行下载。但是当脚本文件下载时,浏览器不会启动其他的并行下载。

当然对各个网站来说,把脚本都放到页面底部加载的可行性还是值得商榷的。就比如阿里巴巴中文站的页面。很多地方有内联的js,页面的显示严重依赖于此,我承认这和无侵入脚本的理念相差甚远,但是很多“历史遗留问题”却不是那么容易解决的。


7.Avoid CSS Expressions 避免CSS Expressions

CSS表达式很可怕,这个只被IE支持的东西执行时候的运算量非常大,你移动一下鼠标它都要进行重计算的,但有时候为了做浏览器的兼容必须要用到这个||| IE6去死去死!~


8.Make JavaScript and CSS External 将JS和CSS外链

前面讲到了缓存这个事情,一些较为公用的JS和CSS,我们可以使用外链的形式,譬如我就是从Google外链来的Jquery文件,如果我的浏览者在浏览别的使用了这个外链文件的网站时已经下载并缓存了这个文件,那么他在浏览我的网站的时候就不需要再进行下载了!~


9.Reduce DNS Lookups 减少DNS查找

在 Internet上域名与IP地址之间是一一对应的,域名(kuqin.com)很好记,但计算机不认识,计算机之间的“相认”还要转成ip地址。在网络 上每台计算机都对应有一个独立的ip地址。在域名和ip地址之间的转换工作称为域名解析,也称DNS查询。一次DNS的解析过程会消耗20-120毫秒的 时间,在dns查询结束之前,浏览器不会下载该域名下的任何东西。所以减少dns查询的时间可以加快页面的加载速度。yahoo的建议一个页面所包含的域 名数尽量控制在2-4个。这就需要对页面整体有一个很好的规划。


10.Minify JavaScript and CSS 减小JS和CSS的体积

写JS和CSS都是有技巧的,用最少的代码实现同样的功能,减少空白,增强逻辑性,用缩写方式等等,当然也有不少工具也能够帮你实现这一点。

压缩js和css的作用很显然,减少页面字节数。容量小页面加载速度自然也就快。而且压缩除了减少体积以外还可以起到一定的保护左右。这点我们做得不错。常用的压缩工具有JsMin、YUI compressor等。另外像http://dean.edwards.name/packer/还给我们提供了一个非常方便的在线压缩工具。你可以在jQuery的网页看到压缩过的js文件和没有压缩过的js文件的容量差别。

当然,压缩带来的一个弊端就是代码的可读性没了。相信很多做前端的朋友都遇到过这个问题:看Google的效果很酷,可是去看他的源代码却是一大堆 挤在一起的字符,连函数名都是替换过的,汗死!自己的代码也这样岂不是对维护非常不方便。所有阿里巴巴中文站目前采用的做法是在js和css发布的时候在 服务器端进行压缩。这样在我们很方便地维护自己的代码。


11. Avoid Redirects 避免重定向

不久前在ieblog上看到过《Internet Explorer and Connection Limits》这篇文章,比如当你输入”http://www.csdn.net” 的时候服务器会自动产生一个301服务器转向”http://www.csdn.net/” ,这种重定向自然也是需要消耗时间的。当然这只是一个例子,发生重定向的原因还有很多,但是不变的是每增加一次重定向就会增加一次web请求,所以因该尽量减少。可以在Apache里用Alias 或者mod_rewrite或者DirectorySlash解决。


12. Remove Duplicate Scripts 删除重复脚本

重复调用的代码浏览器并不会识别忽略,而是会再次运算一遍,这当然是大大的浪费。


13. Configure ETags 配置ETags

Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内 容”,包括图片、脚本、样式表等),是比last-modified date更更加灵活的机制,单位时间内文件被修过多次,Etag可以综合Inode(文件的索引节点(inode)数),MTime(修改时间)和 Size来精准的进行判断,避开UNIX记录MTime只能精确到秒的问题。 服务器集群使用,可取后两个参数。使用ETags减少Web应用带宽和负载。


14. Make Ajax Cacheable 缓存Ajax

Ajax是实时响应的,在浏览器接收到新的数据前,旧的数据被缓存,这样能够更好的提高效率。


15. Flush the Buffer Early 尽早的释放缓冲

当用户进行页面请求时,服务器端需要花费200到500毫秒时间来拼合HTML,将写在head与body之间,释放缓冲,这样可以将文件头先发送出去,然后再发送文件内容,提高效率。


16. Use GET for AJAX Requests 用GET方式进行AJAX请求

Get 方法和服务器只有一次交互(发送数据),而 Post 要两次(发送头部再发送数据)。


17. Post-load Components 延迟加载组件

最先加载必须的组件进行页面初始化,然后再加载其他,YUI Image Loader 是很好的例子。


18. Preload components 预加载组件

提前加载以后可能用到的东西,和延迟加载并不冲突,它的目的是为后续请求提供更快的响应,参见Google首页上的CSS sprites应用。


19. Reduce the Number of DOM Elements 减少DOM元素数量

复杂的页面结构意味着更长的下载及响应时间,更合理更高效的使用标签来架构页面,是好的前端的必备条件。


20. Split Components Across Domains 跨域分离组件

页面组件多个来源可以增大你的平行下载量,但注意不要过多,超过2-4个域名会引起上面说到的DNS查找浪费。


21. Minimize the Number of iframes 减少iframe数量

需要更有效的利用 ifames。
iframe 优点:有利于下载缓慢的广告等第三方内容,安全沙箱,并行下载脚本
iframe 缺点:即使为空也会有较大资源消耗,会阻止页面的onload,非语义


22. No 404s 不要出现404页面

站点本身里(非搜索结果)出现404页面,无意义的404页面会影响用户体验并且会消耗服务器资源。


23. Reduce Cookie Size 减小Cookie

Cookie在服务器及浏览器之间的通过文件头进行交换,尽可能去除不必要的coockie,减小体积,设置合理的过期时间,能够很好的提高效率。


24. Use Cookie-free Domains for Components 对组件使用无Cookie的域名

对静态组件的Cookie读取是一种浪费。确定对于静态内容的请求是无coockie的请求,使用另一个无Cookie的子域名来存放你的静态组件式一个好方法,或者也可以在Cookie中只存放带www的域名。


25. Minimize DOM Access 减少DOM的访问次数

缓存引用访问的元素,JS访问DOM是很慢的,尽量不要用JS来设置页面布局。


26. Develop Smart Event Handlers 开发灵活的事件处理句柄

有时候我们会感觉到页面反应迟钝,这是因为DOM树元素中附加了过多的事件句柄,并且些事件句病被频繁地触发。这就是为什么说使用event delegation(事件代理)是一种好方法了。如果你在一个div中有10个按钮,你只需要在div上附加一次事件句柄就可以了,而不用去为每一个按 钮增加一个句柄。事件冒泡时你可以捕捉到事件并判断出是哪个事件发出的。

 你同样也不用为了操作DOM树而等待onload事件的发生。你需要做的就是等待树结构中你要访问的元素出现。你也不用等待所有图像都加载完毕。

 你可能会希望用DOMContentLoaded事件来代替 事件应用程序中的onAvailable方法。YUI事件工具有一个 onAvailable 方法可以帮助你灵活的设置DOM事件句柄


27. Choose < link >over @import 使用< link >而非 @import

在IE中使用@import就和在页面底部用< link >一样,我们前面说要把< link >放顶部的。所以最好不要使用@import


28. Avoid Filters 避免过滤器的使用

如果需要Alpha透明,不要使用AlphaImageLoader,它效率低下而且只对IE6及以下的版本适用,用PNG8图片。如果你非要使用,加上_filter以免影响IE7+用户。


29. Optimize Images 优化图片

在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小;

将你的GIF转为PNG8会是个减小体积的好办法,另外有很多方法处理你的JPG及PNG图片以达到优化效果。


30. Optimize CSS Sprites 优化CSS Sprites

在CSS Sprites中竖直并尽量紧凑的排列图片,尽量将颜色相似的图片排在一起,会减小图片本身的大小及提高页面图片显示速度。


31. Don’t Scale Images in HTML 不要在HTML中缩放图片

图片要用多大的就用多大的,1000X1000的图片被width=”100″ height=”100″以后,本身的KB数是不会减少的。


32. Make favicon. ico Small and Cacheable 缩小favicon. ico的大小并缓存它

favicon.ico是位于服务器根目录下的一个图片文件。它是必定存在的,因为即使你不关心它是否有用,浏览器也会对它发出请求,因此最好不要 返回一 个404 Not Found的响应。由于是在同一台服务器上,它每被请求一次coockie就会被发送一次。这个图片文件还会影响下载顺序,例如在IE中当你在 onload中请求额外的文件时,favicon会在这些额外内容被加载前下载。

因此,为了减少favicon.ico带来的弊端,要做到:

文件尽量地小,最好小于1K

在适当的时候(也就是你不要打算再换favicon.ico的时候,因为更换新文件时不能对它进行重命名)为它设置Expires文件头。你可以很安全地 把Expires文件头设置为未来的几个月。你可以通过核对当前favicon.ico的上次编辑时间来作出判断。

Imagemagick可以帮你创建小巧的favicon。


33. Keep Components under 25K 保证组件在25K以下

因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重 要。


34. Pack Components into a Multipart Document  将组件打包进一个多部分的文档中

页面内容打包成复合文本就如同带有多附件的Email,它能够使你在一个HTTP请求中取得多个组件(切记:HTTP请求是很奢侈的)。当你使用这条规 则时,首先要确定用户代理是否支持(iPhone就不支持)。


35.Avoid Empty Image src 避免空的图像src属性

空src属性出现的两种形式:

  1. HTML
    <img src="">
  2. JavaScript
    var img = new Image();
    img.src = "";
这两种情况,浏览器会发送一个请求到服务器:

1、IE 请求页面所在的目录。

2、Safari and Chrome 请求页面本身

3、Firefox 3 或者 更早版本 和Safari和Chrome的处理方式相同,但3.5版本解决了这个问题[错误444931]不再发送请求。

4、Opera 不会做任何处理。

如果站点每天数以百万计的页面浏览量,这样大量的突发流量将加大服务器的负荷,浪费服务器资源在一个无用的页面上。