35种加速网站访问的最好做法

from https://developer.yahoo.com/performance/rules.html

最近看了有名的yahoo关于前端性能优化的文章,做了一下笔记。

减少HTTP请求

  1. 减少网页中组件的数量,例如图像,样式表,脚本等。

  2. 将样式表单和脚本组合成单个文件。

  3. CSS Sprites方法,将所有小图标做成一幅图像,设置成背景,用CSS控制具体显示的区域。
    qq.com 中使用的CSS Sprites:

    frontend-performance-rules1.png

  4. Image maps方法,将多个连续的图像组成一幅图像,指定图像不同区域不同的表现(链接等)。不建议。

  5. 使用data: URL scheme将图像植入到页面源代码中,最好是CSS表单中。

使用CDN

增加 Expires 或者 Cache-Control 头

对于长时间不发生变化的组件,例如图片、脚本、样式表等,使用很长的过期时间。
但是当有组件发生变化时,文件的名字必须也发生变化,可以给每个组件的文件名加上版本号。

使用Gzip压缩组件

从HTTP/1.1开始,网页客户端应当在HTTP请求的头部加上Accept-Encoding。表明支持的压缩方法。Gzip是现在最常用的方法。
HTML文档、脚本、样式表以及任何文本的相应例如XML、JSON都应当压缩。
但是图像和PDF文件不应该使用压缩,因为已经被压缩过了。

将样式表放在顶部

这样使得页面是逐渐加载的,已经下载好的内容会立刻显示出来。
放在底部时,很多浏览器会在读取到样式以后再显示内容。

将脚本放在底部

脚本会阻碍并行下载。

避免使用CSS表达式

CSS表达式的调用非常非常的频繁,会影响页面的表现。
好在只有IE支持,并且从IE8开始不在赞成使用了。
使用event handler。

将JavaScript和CSS放在外部

唯一的例外是主页。
可以将主页的JavaScript和CSS放在内部,然后在页面加载完成后动态的下载其他页面需要的JavaScript和CSS。

减少DNS查找

当用户DNS缓存为空时,需要查找的DNS数目和网页中单独的hostname的数目相同,包括网页的URL、图像、脚本、CSS等。
但是将所有内容放在一个主机上又会削弱能同时进行的并行下载数目,因此建议放在2到4个主机上。

简化JavaScript和CSS

减少不必要的字符,例如注释、和空白符号(空格,回车和tab)。
常用的两个用来简化JavaScript的工具有 JSMinYUI Compressor

尽量避免页面跳转

删除重复的Script

配置ETags

Entity tags是一个标记用来使服务器和客户端决定是否已经存储了某个组件。
但是当网站使用了多个服务器时,不同服务器产生的ETag值是不一样的,这就使得即便已经缓存了某个组件,但是依然需要下载。
如果没有从ETags提供的模型得到好处,那就最好整个移除ETag。
这篇文章Microsoft Support article描述了怎么移除ETags。

使ajax可以缓存

ajax可以提供异步显示页面的效果,但是并不等于立刻显示。
可以像这篇文章中描述的一样Add an Expires or a Cache-Control Header,使ajax可以被缓存。
上面的有些做法也可以应用到ajax,例如 压缩组件、减少DNS查找、精简JavaScript、避免重定向、配置Etags。

在早的时刻flush缓存中的内容

当用户请求一个页面时,服务器需要至少200ms到500ms用来组合html页面。这段时间浏览器是停滞的。
可以使用PHP中的flush()函数,这个函数使得你可以将已经完成的html部分先发给客户端。
一个好的使用flush()函数的地方是紧跟在head后面,这使得浏览器可以提前开始下载head中引用的js、css等。

使用GET方法来请求ajax

POST方法分成了两步,先发送头,再发送内容。
而GET方法之使用一个TCP包 。

后加载组件

有些组件可以在页面load完成以后再进行下载。
JavaScript文件适合后加载,因为有些动作例如拖拽等效果只有在页面完成加载以后才能操作。
其他的适合后加载的有隐藏的内容(用户某些动作以后才会加载的内容)和折叠中的图像。
YUI Image Loader工具使得你可以延迟加载在折叠中的图像。
YUI Get utility是一个简单的方法动态加载JS和CSS。

预加载组件

提前加载之后可能需要的组件。
几种预加载的类型:无条件预加载、有条件预加载、期望预加载(用于页面有变动时,提前下载下一个版本的页面 )。

减少DOM元素的数目

DOM元素数目过多会使得JS在使用DOM的时候变慢。尽量用少的DOM元素。
YUI CSS utilities可以帮助布局:grids.css帮助整体布局、fonts.css和reset.css帮助去掉浏览器默认的格式。
可以使用document.getElementByTagName(‘*’).length 看有多少个DOM元素。

将组件分散在不同域名上

将组件分散可以最大化并行下载的数目,但是会增加DNS的查找。
最好是使用2-4个域名。

减少iframes的数目

iframes的好处:

  1. 对比较慢的第三方内容有帮助。
  2. 安全的沙盒。
  3. 并行下载脚本。

iframes的坏处:

  1. 即使是空白也会有消耗。
  2. 阻止了页面的加载(onload)。
  3. 非语义的。

不要404

HTTP请求是花费很大的,因此没有必要为了返回无用的响应(例如404 Not Found)来产生一个HTTP请求。
尤其是link中的外部脚本是错的,结果返回一个404。首先,这个下载会阻碍并行下载。其次,浏览器也许会尝试解析404响应中的body部分,认为body中是JavaScript。

减小Cookie的大小

更多的信息参考这篇文章:”When the Cookie Crumbles“。

需要记住的是:

  1. 省略不必要的Cookies。
  2. 保持cookie尽量的小,来最小化其对用户响应时间的影响。
  3. 留心在合适的域名等级设置cookie,确保其他子域名不受影响。
  4. 设置合适的到期时间(Expires date),比较早的或者没有的(none)到期时间使得cookie删除的更快,提高了用户的响应时间。(???)

对于组件使用没有cookie的域名

浏览器请求静态组件(例如图像)时,一起发送的cookies没有任何用处。
创建一个子域名,作为静态组件的主机。
如果已经在顶级域名上设置了cookie(example.org 而不是www.example.org),那么就需要重新注册一个域名。

减少DOM的存取

使用JavaScript操作DOM元素比较慢。
为了得到更好的效果,应当:
缓存已经取得的元素。
将节点在线下更新好以后再将他们整个加入到DOM树中。(使用文档片段 DocumentFragment)
避免用JavaScript固定布局。
更多信息,check the YUI theatre’s “High Performance Ajax Applications“ by Julien Lecomte.

开发智能的event handler

如果将太多的事件处理程序绑定在DOM树上,网页将会变慢。
因此推荐使用事件授权,在父元素上设置事件处理程序,在程序中判断来自哪个子元素。
使用onload要等到页面完全加载完成,而我们只需要保证要操作的DOM元素加载完成就行了。可以使用DOMContentLoaded事件。
但是要注意的是不是所有浏览器都支持:

frontend-performance-rules2.png

选择<link>而不是@import

前面说过CSS应当放在顶部,从而浏览器可以渐进的渲染。
而在IE中@import变现的就像你将<link>放在底部一样,因此最好不要使用。

避免过滤器

IE中有一个AlphaImageLoader过滤器用来在小于7的IE版本上修复一个半透明真彩PNG图像的问题。
这个过滤器会阻止里卢兰其的渲染,并且在图像下载时冻结浏览器。还会增加内存的消耗,它是应用在每个元素上的,不是每个图像上的,所以问题很多。
最好避免使用该过滤器,可以使用IE支持的PNG8。
如果必须要使用AlphaImageLoader,使用_filter。

优化图像

在设计师制作好网站上的图像后,有一些优化可以尝试。

  1. 可以检查GIF图像使用的调色板大小是否和图像中的颜色数目一致。使用imagemagick可以方便的检查identify -verbose image.gif。
  2. 尝试将GIF转化成PNG看是不是会有节省。通常来说是会节省的。
    这个imagemagick语句可以得到浏览器支持的PNG图像:convert image.gif image.png。
  3. 对PNG图像使用pngcrush 或其他PNG图像优化工具。pngcrush image.png -rem alla -reduce -brute result.png
  4. 对JPEG图像使用jpegtran,这个工具可以对图像做一些低损耗的操作例如旋转等。并且也可以用来对图像进行优化,去除注释和其他无用的信息。jpegtran -copy none -optimize -perfect src.jpg dest.jpg

优化CSS雪碧图

  1. 将图像水平排列通常会使得文件体积更小。
  2. 将相似的颜色组合可以使得颜色的数目较少,理想状态下是小于256种颜色,这样可以使用PNG8格式。
  3. 要适合移动设备,不要再图像之间留太大的空隙。这不会对文件的大小有显著影响,但是当客户端解压缩文件的时候需要的内存更小。

不要在HTML中缩放图像

不要因为你可以在HTML中设置图像的大小就使用一个超过你需要大小的图像。

使favicon.ico小并且可以缓存

favicon.ico是存放在你服务器根部的一个图像。
尽管你可能不需要,但是浏览器依旧会请求它,所以最好不要响应一个404 Not Found。
确保:

  1. 它很小,最好小于1K.
  2. 设置合适的过期时间。Imagemagick 可以用来获得小的favicons。

保持组件小于25K

这个约束是因为iPhone不会缓存大于25K的组件。需要注意的是这是解压以后的大小。因此仅仅gzip是不够的。
更多信息可以看”Performance Research, Part 5: iPhone Cacheability - Making it Stick“ by Wayne Shea and Tenni Theurer.

将组件打包成多部分的文档

将组件打包成多部分的文档就像是一个含有附件的email,可以用一个HTTP请求得到多个组件。
(根据stackoverflow上的这个问题,似乎只有IE能很好的支持)

避免空的图像src

带有空src属性的图像会在两种情况下发生:

  1. HTML

    1
    <img src="">
  2. JavaScript

    1
    2
    var img = new Image();
    img.src = "";

这两种情况都会导致浏览器对服务器产生另一个请求:

  1. IE会想页面所在的目录产生一个请求。
  2. Safari和Chrome会向页面本身产生一个请求。
  3. Firefox 3及之前的版本会和Safari、Chrome表现的一样,之后的版本修复了这个BUG。
  4. Opera不会做任何事情。

为什么这很糟糕呢?

  1. 会对服务服务器造成很多无用的流量。
  2. 浪费了服务器的计算周期,生成了一个从来不会使用的页面。
  3. 也许会破坏用户数据。例如在请求中的追踪用户的偏好。