雅虎前端优化35条规则

本文是大名鼎鼎的雅虎前端优化规则(Yslow)的翻译。翻译并不逐字逐句,部分难以逐字翻译的被意译了,另一些不重要的举例等也被精简。php

原文: Best Practices for Speeding Up Your Web Sitecss

如何让web页面更快,雅虎团队实践总结了7类35条规则,下面一一列出。html

1. Content

1.1 Make Fewer HTTP Requests

Minimize HTTP Requests减小/最小化 http 请求数。前端

到终端用户的响应时间80%花在前端:大部分用于下载组件(js/css/image/flash等等)。减小组件数就是减小渲染页面所需的http请求数。这是更快页面的关键。html5

减小组件数的一个方法就是简化页面设计。保持富内容的页面且能减小http请求,有如下几个技术:web

  • Combined files。合并文件,如合并js,合并css都能减小请求数。若是页面间脚本和样式差别很大,合并会更具挑战性。
  • CSS Sprites。雪碧图能够合并多个背景图片,经过background-image 和 background-position 来显示不一样部分。
  • Image maps。合并多个图片到一个图片,通常用于如导航条。因为定义坐标的枯燥和易错,通常_不推荐_。
  • Inline images。使用data:url scheme来內连图片。

减小请求数是为第一次访问页面的用户提升性能的最重要的指导。ajax

1.2 Reduce DNS Lookups

减小DNS查询。express

就像电话簿,你在浏览器地址栏输入网址,经过DNS查询获得网站真实IP。json

DNS查询被缓存来提升性能。这种缓存可能发生在特定的缓存服务器(ISP/local area network维护),或者用户的计算机。DNS信息留存在操做系统DNS缓存中(在windows中就是 DNS Client Serve )。大多浏览器有本身的缓存,独立于操做系统缓存。只要浏览器在本身的缓存里有某条DNS记录,它就不会向操做系统发DNS解析请求。windows

IE默认缓存DNS记录30分钟,FireFox默认缓存1分钟。

当客户端的DNS缓存是空的,DNS查找次数等于页面中的惟一域名数。

减小DNS请求数可能会减小并行下载数。避免DNS查找减小响应时间,但减小并行下载数可能会增长响应时间。指导原则是组件能够分散在至少2个但很少于4个的不一样域名。这是二者的妥协。

1.3 Avoid Redirects

避免跳转。

跳转用301302状态码来达成。一个301响应http头的例子:

HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html

浏览器自动跳转到Location指定的路径。跳转所需的全部信息都在http头,因此http主体通常是空的。301 302响应通常不会被缓存,除非有额外的头部信息,好比ExpiresCache-Control指定要缓存。meta刷新标签或 JavaScript 也能够跳转,但若是真要跳转,3xx跳转更好,主要是保证返回键可用。

跳转显然拖慢响应速度。在跳转的页面被获取前浏览器没什么能渲染,没什么组件能下载。

最浪费的跳转之一发生在url尾部slash(/)缺失。好比http://astrology.yahoo.com/astrology301跳转到http://astrology.yahoo.com/astrology/。这能够被Apache等服务器修复,用Aliasmod_rewrite等等。

1.4 Make Ajax Cacheable

让Ajax可缓存。

使用ajax的好处是能够向用户提供很快的反馈,由于它是向后台异步请求数据。可是,这些异步请求不保证用户等待的时间——异步不意味着瞬时。

提升ajax性能的最重要的方法是让响应被缓存,即在Add an Expires or a Cache-Control Header中讨论的 Expires 。其它方法是:

  • gzip组件
  • 减小DNS查找
  • 压缩JS
  • 避免跳转
  • 设置ETags

1.5 Post-load Components

延迟加载组件。

再看看你的页面而后问问本身,“什么是页面初始化必须的?”。剩下的内容和组件能够延迟。

JavaScript是理想的(延迟)候选者,能够切分到onload事件以前和以后。好比拖放的js库能够延迟,由于拖动必须在页面初始化以后。其它可延迟的包括隐藏的内容,折叠起来的图片等等。

1.6 Preload Components

预加载组件。

预加载看起来与延迟加载相反,但它的确有个不一样的目标。经过预加载你能够利用浏览器的空闲时间来请求你未来会用到的组件。这样当用户访问下一个页面时,你会有更多的组件已经在缓存中,这样会极大加快页面加载。

有几种预加载类型:

  • 无条件预加载:一旦onload触发,你当即获取另外的组件。好比谷歌会在主页这样加载搜索结果页面用到的雪碧图。
  • 有条件预加载:基于用户动做,你推测用户下一步会去哪里并加载相应组件。
  • 预期的预加载:在发布从新设计(的网站)前提早加载。在旧网页预加载新网页的部分组件,那么切换到新网页时就不会是没有任何缓存了。

1.7 Reduce the Number of DOM Elements

减小dom数。

一个复杂的页面意味着更多的内容要下载,以及更慢的dom访问。好比在有500dom数量的页面添加事件处理就和有5000dom数量的不一样。

若是你的页面dom元素不少,那么意味着你可能须要删除无用的内容和标签来优化。

1.8 Split Components Across Domains

把组件分散到不一样的域名。

把组件分散到不一样的域名容许你最大化并行下载数。因为DNS查询的反作用,最佳的不一样域名数是2-4。

1.9 Minimize the Number of iframes

最小化iframe的数量。

iframe容许html文档被插入到父文档。

<iframe>优势:

  • 帮助解决缓慢的第三方内容的加载,如广告和徽章
  • 安全沙盒
  • 并行下载脚本

<iframe>缺点:

  • 即便空的也消耗(资源和时间)
  • 阻塞了页面的onload
  • 非语义化(标签)

1.10 No 404s

不要404。

http请求是昂贵的,因此发出http请求但得到没用的响应(如404)是彻底没必要要的,而且会下降用户体验。

一些网站会有特别的404页面提升用户体验,但这仍然会浪费服务器资源。特别坏的是当连接指向外部js但却获得404结果。这样首先会下降(占用)并行下载数,其次浏览器可能会把404响应体看成js来解析,试图从里面找出可用的东西。

2. Server

2.1 Use a Content Delivery Network

使用CDN。

用户接近你的服务器会减小响应时间。把你的内容发布到多个,地理上分散的服务器可让页面加载更快。但怎么开始?

首先不要试图把你的架构从新设计成分布式架构。由于可能引进更多复杂性和不可控。

记住80-90%的终端用户响应时间花费在下载页面中的全部组件:图片、样式、脚本、falsh等等。这是_Performance Golden Rule_。不要从困难的从新设计后台架构开始,最好首先分发你的静态内容。这不只能够减小响应时间,用CDN还很容易来作。

CDN是一群不一样地点的服务器,能够更高效地分发内容到用户。一些大公司有本身的CDN。

2.2 Add an Expires or a Cache-Control Header

Expires或者Cache-Control头部。

这条规则有两个方面:

  • 对静态组件:经过设置Expires头部来实现“永不过时”策略。
  • 对动态组件:用合适的Cache-Control头部来帮助浏览器进行有条件请求。

页面愈来愈丰富,意味着更多脚本,样式,图片等等。第一次访问的用户可能须要发出多个请求,但使用Expires可让这些组件被缓存。这避免了访问子页面时不必的http请求。Expires通常用在图片上,但应该用在全部的组件上。

浏览器(以及代理)使用缓存来减小http请求数,加快页面加载。服务器使用http响应的Expires头部来告诉客户端一个组件能够缓存多久。好比下面:

Expires: Thu, 15 Apr 2010 20:00:00 GMT //2010-04-15以前都是稳定的

注意,若是你设置了Expires头部,当组件更新后,你必须更改文件名。

2.3 Gzip Components

传输时用gzip等压缩组件。

http请求或响应的传输时间能够被前端工程师显著减小。终端用户的带宽,ISP,接近对等交换点等等无法被开发团队控制,可是,压缩能够经过减小http响应的大小减小响应时间。

HTTP/1.1开始,客户端经过http请求中的Accept-Encoding头部来提示支持的压缩:

Accept-Encoding: gzip, deflate

若是服务器看到这个头部,它可能会选用列表中的某个方法压缩响应。服务器经过Content-Encoding头部提示客户端:

Content-Encoding: gzip

gzip通常可减少响应的70%。尽量去gzip更多(文本)类型的文件。html,脚本,样式,xml和json等等都应该被gzip,而图片,pdf等等不该该被gzip,由于它们自己已被压缩过,gzip它们只是浪费cpu,甚至增长文件大小。

2.4 Configure ETags

实体标记(Entity tags,ETag)是服务器和浏览器之间判断浏览器缓存中某个组件是否匹配服务器端原组件的一种机制。实体就是组件:图片,脚本,样式等等。ETag被看成验证明体的比最后更改(last-modified)日期更高效的机制。服务器这样设置组件的ETag:

HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195

以后,若是浏览器要验证组件,它用If-None-Match头部来传ETag给服务器。若是ETag匹配,服务器返回304:

GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified

ETag的问题是它们被构造来使它们对特定的运行这个网站的服务器惟一。浏览器从一个服务器获取组件,以后向另外一个服务器验证,ETag将不匹配。然而服务器集群是处理请求的通用解决方案。

若是不能解决多服务器间的ETag匹配问题,那么删除ETag可能更好。

2.5 Flush the Buffer Early

早一点刷新buffer(尽早给浏览器数据)。

当用户请求一个页面,服务器通常要花200-500ms来拼凑整个页面。这段时间,浏览器是空闲的(等数据返回)。在php,有个方法flush()容许你传输部分准备好的html响应给浏览器。这样的话浏览器就能够开始下载组件,而同时后台能够继续生成页面剩下的部分。这种好处更可能是在忙碌的后台或轻前端网站能够看到。

一个比较好的flush的位置是在head以后,由于浏览器能够加载其中的样式和脚本文件,然后台继续生成页面剩余部分。

<!-- css, js --> </head> <?php flush(); ?> <body> <!-- content -->

2.6 Use GET for AJAX Requests

ajax请求用get。

Yahoo! Mail团队发现当使用XMLHttpRequest,POST 被浏览器实现为两步:首先发送头部,而后发送数据。因此使用GET最好,仅用一个TCP包发送(除非cookie太多)。IE的url长度限制是2K。

POST但不提交任何数据根GET行为相似,但从语义上讲,获取数据应该用GET,提交数据到服务器用POST。

2.7 Avoid Empty Image src

避免空src的图片。

空src属性的图片的行为可能跟你预期的不同。它有两种形式:

  1. html标签:<img src="">
  2. js:var img = new Image(); img.src = "";

两种都会形成同一种后果:浏览器会向你的服务器发请求。

  • IE,向页面所在的目录发请求。
  • Safari和Chrome,请求实际的页面。
  • FireFox3及以前和Safari/Chrome同样,但从3.5开始修复问题,再也不发请求。
  • Opera遇到空图片src不作任何事。

为何这种行为很糟糕?

  1. 因为发送大量的意料以外的流量,会削弱服务器,尤为那些天天pv上百万的页面。
  2. 浪费服务器计算周期取生成不会被浏览的页面。
  3. 可能会破坏用户数据。若是你在跟踪请求状态,经过cookie或其它,你可能会破坏数据。即便image的请求不会返回图片,但全部的头部数据都被浏览器读取了,包括cookie。即便剩下的响应体被丢弃,破坏可能已经发生。

这种行为的根源是uri解析发生在浏览器。RFC 3986 定义了这种行为,空字符串被看成相对路径,Firefox, Safari, 和 Chrome都正确解析,而IE错误。总之,浏览器解析空字符串为相对路径的行为被认为是符合预期的。

html5在_4.8.2_添加了对标签src属性的描述,指导浏览器不要发出额外的请求。

The src attribute must be present, and must contain a valid URL referencing a non-interactive, optionally animated, image resource that is neither paged nor scripted. If the base URI of the element is the same as the document's address, then the src attribute's value must not be the empty string.

幸运的是未来浏览器不会有这个问题了(在图片上)。不幸的是,<script src=""><link href="">没有这样的规范。

3 Cookie

3.1 Reduce Cookie Size

http cookie的使用有多种缘由,好比受权和个性化。cookie的信息经过http头部在浏览器和服务器端交换。尽量减少cookie的大小来下降响应时间。

  • 消除没必要要的cookie。
  • 尽量减少cookie的大小来下降响应时间。
  • 注意设置cookie到合适的域名级别,则其它子域名不会被影响。
  • 正确设置Expires日期。早一点的Expires日期或者没有会尽早删除cookie,优化响应时间。

3.2 Use Cookie-free Domains for Components

用没有cookie的域名提供组件。

当浏览器请求静态图片并把cookie一块儿发送到服务器时,cookie此时对服务器没什么用处。因此这些cookie只是增长了网络流量。因此你应该保证静态组件的请求是没有cookie的。能够建立一个子域名来托管全部静态组件。

好比,你域名是www.example.org,能够把静态组件托管在static.example.org。不过,你若是把cookie设置在顶级域名example.org下,这些cookie仍然会被传给static.example.org。这种状况下,启用一个全新的域名来托管静态组件。

另一个用没有cookie的域名提供组件的好处是,某些代理可能会阻止缓存待cookie的静态组件请求。

4. CSS

4.1 Put Stylesheets at the Top

把样式放在顶部。

研究雅虎网页性能时发现把样式表移到<head>里会让页面更快。这是由于把样式表移到<head>里容许页面逐步渲染。

关注性能的前端工程师但愿页面被逐步渲染,这时由于,咱们但愿浏览器尽早渲染获取到的任何内容。这对大页面和网速慢的用户很重要。给用户视觉反馈,好比进度条的重要性已经被大量研究和记录。在咱们的状况中,HTML页面就是进度条。当浏览器逐步加载页面头部,导航条,logo等等,这些都是给等待页面的用户的视觉反馈。这优化了总体用户体验。

把样式表放在文档底部的问题是它阻止了许多浏览器的逐步渲染,包括IE。这些浏览器阻止渲染来避免在样式更改时须要重绘页面元素。因此用户会卡在白屏。

HTML规范清楚代表样式应该在<head>里。

4.2 Avoid CSS Expressions

避免CSS表达式。

CSS表达式是强大的(可能也是危险的)设置动态CSS属性的方法。IE5开始支持,IE8开始不同意使用。例如,背景颜色能够设置成每小时轮换:

background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );

CSS表达式的问题是它们可能比大多数人预期的计算的更频繁。它们不只在页面载入和调整大小时从新计算,也在滚动页面甚至是用户在页面上移动鼠标时计算。好比在页面上移动鼠标可能轻易计算超过10000次。

要避免CSS表达式计算太屡次,能够在它第一次计算后替换成确切值,或者用事件处理函数而不是CSS表达式。

4.3 Choose <link> over @import

选择<link>而不是@import

以前的一个最佳原则是说CSS应该在顶部来容许逐步渲染。

在IE用@import和把CSS放到页面底部行为一致,因此最好别用。

4.4 Avoid Filters

避免使用(IE)过滤器。

IE专有的AlphaImageLoader过滤器用于修复IE7如下版本的半透明真彩色PNG的问题。这个过滤器的问题是它阻止了渲染,并在图片下载时冻结了浏览器。另外它还引发内存消耗,而且它被应用到每一个元素而不是每一个图片,因此问题(的严重性)翻倍了。

最佳作法是放弃AlphaImageLoader,改用PNG8来优雅降级。

5. JavaScript

5.1 Put Scripts at the Bottom

把脚本放到底部。

脚本引发的问题是它们阻塞了并行下载。HTTP1.1规范建议浏览器每一个域名下不要一次下载超过2个组件。若是你的图片分散在不一样服务器,那么你能并行下载多个图片。但当脚本在下载,浏览器不会再下载其它组件,即便在不一样域名下。

有些状况下把脚本移动到底部并不简单。好比,脚本中用了document.write来插入内容,它就不能被移动到底部。另外有可能有做用域问题。但大多数状况,有方法能够解决这些问题。

一个替代建议是使用异步脚本。defer属性代表脚本不包含document.write,是提示浏览器继续渲染的线索。不幸的是,Firefox不支持。若是脚本能异步,那么也就能够移动到底部。

5.2 Make JavaScript and CSS External

使用外部JS和CSS。

这里的不少性能规则涉及外部组件怎么管理。但你首先要明白一个基本问题:JS和CSS是应该包含在外部文件仍是內连在页面自己?

真实世界中使用外部文件通常会加快页面,由于JS和CSS文件被浏览器缓存了。內连的JS和CSS怎在每次HTML文档下载时都被下载。內连减小了http请求,但增长了HTML文档大小。另外一方面,若是JS和CSS被缓存了,那么HTML文档能够减少大小而不增长HTTP请求。

核心因素,就是JS和CSS被缓存相对于HTML文档被请求的频率。尽管这个因素很难被量化,但能够用不一样的指标来计算。若是网站用户每一个session有多个pv,许多页面重用相同的JS和CSS,那么有很大可能用外部JS和CSS更好。

许多网站用这些指标计算后在中间位置。对这些网站来讲,最佳方案仍是用外部JS和CSS文件。惟一例外是內连更被主页偏心,如http://www.yahoo.com/。主页每一个session可能只有少许的甚至一个pv,这时候內连可能更快。

对多个页面的首页来讲,能够经过技术减小(其它页面的)http请求。在首页用內连,初始化后动态加载外部文件,接下来的页面若是用到这些文件,就可使用缓存了。

5.3 Minify JavaScript and CSS

压缩JS和CSS。

压缩就是删除代码中没必要要的字符来减少文件大小,从而提升加载速度。当代码压缩时,注释删除,不须要的空格(空白,换行,tab)也被删除。

混淆是对代码可选的优化。它比压缩更复杂,而且可能产生bug。在对美国top10网站的调查,压缩可减少21%,而混淆可减少25%。

除了外部脚本和样式,內连的脚本和样式一样应该被压缩。

5.4 Remove Duplicate Scripts

删除重复的脚本。

在页面中引入相同的脚本两次会伤害性能。可能超出你的预料,美国top10网站的2家有重复脚本引入。两个主要因素形成同一页面引入相同脚本:团队大小和脚本数量。当确实引入重复脚本,会发出没必要要的http请求和浪费js执行时间。

发出没必要要的http请求发生在IE而不是Firefox。在IE,若是外部脚本引入两次且没有缓存,它会发出2个请求。即便脚本被缓存,刷新时也会发出额外请求。

除了增长http请求,时间被浪费在执行脚本屡次上。无论IE仍是Firefox都会执行屡次。

一种避免屡次引入脚本的方法是在模板系统实现一个脚本管理模块。

5.5 Minimize DOM Access

最小化DOM访问。

用JS访问DOM元素是缓慢的,因此为了响应更好的页面,你应该:

  • 缓存访问过的元素的引用
  • 在DOM树外更新节点,而后添加到DOM树
  • 避免用JS实现固定布局

5.6 Develop Smart Event Handlers

开发聪明的事件处理

有时候页面看起来不那么响应(响应速度慢),是由于绑定到不一样元素的大量事件处理函数执行太屡次。这是为何使用_事件委托_是一种好方法。

另外,你没必要等到onload事件来开始处理DOM树,DOMContentLoaded更快。大多时候你须要的只是想访问的元素已在DOM树中,因此你没必要等到全部图片被下载。

6 Images

6.1 Optimize Images

优化图片

在设计师建好图片后,在上传图片到服务器前你仍能够作些事:

  • 检查gif图片的调色板大小是否匹配图片颜色数。
  • 能够把gif转成png看看有没有变小。除了动画,gif通常能够转成png8。
  • 运行pngcrush或其它工具压缩png。
  • 运行jpegtran或其它工具压缩jpeg。

6.2 Optimize CSS Sprites

优化CSS雪碧图

  • 把图片横向合并而不是纵向,横向更小。
  • 把颜色近似的图片合并到一张雪碧图,这样可让颜色数更少,若是低于256就能够用png8.
  • "Be mobile-friendly"而且合并时图片间的间距不要太大。这对图片大小影响不是太大,但客户端解压时须要的内存更少。100×100是10000个像素,1000×1000是1000000个像素。

6.3 Don't Scale Images in HTML

不要在html中缩放图片

不要由于你能够设置图片的宽高就去用比你须要的大得多的图片。若是你须要

<img width="100" height="100" src="mycat.jpg" alt="My Cat" /> 

那么,就用100x100px的图片,而不是500x500px的。

6.4 Make favicon.ico Small and Cacheable

favicon.ico小且缓存

favicon.ico是在你服务器根路径的图片。邪恶的是即便你不关心它,浏览器仍然会请求它。因此最好不要响应404。另外因为在同一服务器,每次请求favicon.ico时也会带上cookie。这个图片还会影响下载顺序,好比在IE,若是你在onload时下载额外的组件,fcvicon会在这些组件以前被下载。

怎么减轻favicon.ico的缺点?

  • 小,最好1K如下
  • 设置Expires头部。也许能够安全地设置为几个月。

7 Mobile

7.1 Keep Components under 25K

保持组件小于25K

这个限制与iPhone不缓存大于25K的组件相关。注意,这是非压缩(uncompressed)的文件大小。在这里minification(压缩,不要与compress混淆)很重要,由于gzip没法知足(iPhone)。

7.2 Pack Components into a Multipart Document

打包组件到一个多部父文档

打包组件到一个多部父文档相似于带附件的邮件。它帮助你在一个http请求中获取多个组件,但注意,iPhone不支持。

 

 

具体的关于优化的知识点或问题

1. 为何网页设置缓存后仍然有请求(304响应)?

浏览器刷新是conditional request,因此若是经过刷新来看缓存是否有效确定是304。能够试试输入网址按回车或者回退键来看效果。另外因为HTML文档不多设置彻底缓存(通常要和服务器验证),能够看静态组件的缓存效果(200 ok (from cache))。

2. expirationTime = responseTime + freshnessLifetime - currentAge

freshnessLifetime具体怎么算能够参考https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching_FAQ。

3. Flash of unstyled content(无样式内容闪烁)

Flash of unstyled content(FOUC)就是在加载外部样式表以前,浏览器按默认样式显示了内容,这是由于浏览器在全部资源都下载好前就开始渲染页面了。一旦外部样式被加载,浏览器就会修正样式,但这种修正多是可见的,也就是FOUC。

怎么避免?在<head>中经过<link>引入样式,避免使用@import

相关文章
相关标签/搜索