本文大部份内容翻译自雅虎前端的性能优化,如何让页面加载更快,雅虎给出了多个规则,原文地址:Best Practices for Speeding Up Your Web Site 。主要从八个方向分别介绍了如何进行性能的优化。php
雅虎军规上说明80%的响应时间都来自前端,大多数页面的加载时间都是在下载图片,样式,js,flash等,减小组件的数量反过来减小请求的数量是页面加载更快的关键。css
减小页面组件数量的一种方法是简化页面设计,可是如何在构建更丰富内容的基础上,同时还能减小相应时间?html
JavaScript
,CSS
文件来减小HTTP请求的数量来缩短响应时间。background-image
和background-position
属性来显示部分须要的图像。data:url scheme
将图像嵌入实际页面中。DNS就像电话簿将人们的姓名映射到他们的电话号码同样,当您输入www.yahoo.com
时,浏览器会经过DNS解析返回服务器的IP地址,这个DNS解析过程须要成本,一般须要20-120ms才能解析成功,在这以前,浏览器没法从服务器获取任何内容。前端
经过缓存DNS查找来得到更好的性能。DNS信息保留在操做系统的DNS缓存中,大多数的浏览器都有本身的缓存,与操做系统的分开。express
默认状况,IE会将DNS查找缓存30分钟,FireFox缓存一分钟。json
当客户端的DNS缓存为空(对于浏览器和操做系统)时,DNS查找的数量等于网页中惟一主机名的数量。 减小惟一主机名的数量可减小DNS查找的数量。后端
减小惟一主机名的数量有可能减小页面中发生的并行下载量。避免DNS查找会缩短响应时间,但减小并行下载可能会缩短响应时间。 准则是将这些组件分红至少两个但不超过四个主机名。这是减小DNS查找和容许高度并行下载之间的良好折衷。跨域
使用301和302状态码完成重定向。下面是一个301响应http头示例:浏览器
HTTP/1.1 301 Moved Permanently Location: http://example.com/newuri Content-Type: text/html
浏览器自动将用户带到Location
字段指定的URL。跳转所需的全部信息都在http头 ,响应的主体一般是空的。301或302响应通常不会被缓存,除非有Expires
或者Cache-Control
指定要缓存。缓存
要记住的主要事情是重定向会下降用户体验。在用户和HTML文档之间插入重定向会延迟页面中的全部内容,由于页面中的任何内容都没法呈现,而且在HTML文档到达以前不会开始下载任何组件。
最浪费的重定向之一常常发生,就是在URL中缺乏尾部/
会产生301响应,好比http://astrology.yahoo.com/astrology
会301
跳转到http://astrology.yahoo.com/astrology/
。
使Ajax可缓存的好处之一就是在用户请求时能够提供快速反馈,由于它从后端Web服务器异步请求信息。重要的是要记住“异步”并不意味着“瞬时”。
为了提升性能,优化这些Ajax响应很是重要。提升Ajax性能的最重要方法是使响应可缓存,其中提升的方法除了Add an Expires or a Cache-Control Header 中讨论的以外,其余方法还有:
你能够自习看看你的页面并问问你本身,最初页面的渲染须要什么,其余的内容和组件就是能够延迟加载的。
JavaScript
是在 onload
时间以前和以后拆分的理想候选者,例如,若是您有拖放和动画的JS代码,则能够延迟加载,由于它须要在页面渲染完以后才能够执行。其它可延迟的包括隐藏的内容,折叠起来的图片等等。
预加载看起来和延迟加载相反,但它实际上有着不一样的目标,经过预加载组件,您能够利用浏览器空闲的时间并请求未来须要的组件(如图像,样式和脚本)。这样,当用户访问下一页时,您能够将大部分组件放在缓存中,而且用户加载页面将更快。
有几种预加载类型:
onload
触发,你当即获取另外的组件。好比谷歌会在主页这样加载搜索结果页面用到的雪碧图。复杂页面意味着要下载更多字节,这也意味着JavaScript中的DOM访问速度更慢。例如,当您想要添加事件处理程序时,若是在页面上循环遍历500或5000个DOM元素,则会有所不一样。
拆分组件来达到最大化的并行下载,因为DNS查询的反作用,最好保证使用的域名不许超过2-4个。例如,您能够托管HTML和动态内容,www.example.org
并在static1.example.org
和之间拆分静态组件。
iframe容许html文档被插入到父文档。
<iframe>
优势:
<iframe>
缺点:
onload
HTTP的请求是很是昂贵的,所以发出的HTTP请求得到无用的响应是彻底没有必要的,而且会影响用户体验。
一些网站会有特别的404页面提升用户体验,但这仍然会浪费服务器资源。特别坏的是当连接指向外部js但却获得404结果。这样首先会下降(占用)并行下载数,其次浏览器可能会把404响应体看成js来解析,试图从里面找出可用的东西。
用户与Web服务器的距离会对响应时间产生影响。在多个地理位置分散的服务器上部署内容将使您的页面从用户的角度加载更快。
CDN是一群不一样地点的服务器,能够更高效地分发内容到用户。
Expries
或者 Cache-Control
头这条规则有两个方面:
Expires
头实现“永不过时”策略Cache-Control
标头来帮助浏览器处理条件请求页面内容愈来愈丰富,意味着页面中有更多脚本,样式表,图像以及Flash。您的页面的首次访问可能必须发出多个HTTP请求,但经过使用Expires标头,您可使这些组件可缓存。
浏览器(和代理)使用缓存来减小HTTP请求的数量和大小,从而加快网页加载速度。Web服务器使用HTTP响应中的Expires头来告诉客户端能够缓存组件多长时间。 好比:
Expires: Thu, 15 Apr 2010 20:00:00 GMT
表示在2010-04-15均可以请求缓存内容。
经过前端工程师作出的决策,能够显著减小在网络上传输HTTP请求和响应所需的时间。从HTTP / 1.1开始,Web客户端表示支持使用HTTP请求中使用Accept-Encoding进行压缩。
Accept-Encoding:gzip,deflate
若是服务器看到这个头部,它可能会选用列表中的某个方法压缩响应。服务器经过Content-Encoding
头部提示客户端:
Content-Encoding: gzip
gzip通常可减少响应的70%。尽量去gzip更多(文本)类型的文件。html,脚本,样式,xml和json等等都应该被gzip,而图片,pdf等等不该该被gzip,由于它们自己已被压缩过,gzip压缩它们只是浪费cpu,甚至增长文件大小。
尽量多地压缩文件类型是减轻页面重量和加速用户体验的简便方法。
实体标记(ETag)是Web服务器和浏览器用于肯定浏览器缓存中的组件是否与源服务器上的组件匹配的机制。 添加ETag以提供验证比上次修改日期更灵活的实体的机制。ETag是惟一标识组件的特定版本的字符串。 服务器这样设置组件的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
当用户请求页面时,后端服务器可能须要200到500毫秒才能将HTML页面拼接在一块儿。在此期间,浏览器在等待数据到达时处于空闲状态。 在PHP中,有函数flush()
。它容许您将部分准备好的HTML响应发送到浏览器,以便浏览器能够在后端忙于HTML页面的其他部分时开始获取组件。这种好处主要出如今繁忙的后端或轻量级前端。
一个比较好的flush的位置是在head
以后,由于浏览器能够加载其中的样式和脚本文件,然后台继续生成页面剩余部分。
<!-- css, js --> </head> <?php flush(); ?> <body> <!-- content -->
在雅虎邮件团队发现,在使用时XMLHttpRequest
,POST在浏览器中实现为两步过程:首先发送头部,而后发送数据。所以最好使用GET,它只须要一个TCP数据包发送(除非你有不少cookie)。IE中的最大URL长度为2K,所以若是发送的数据超过2K,则可能没法使用GET。
POST不提交任何数据跟GET行为相似,但从语义上讲,获取数据应该用GET,提交数据到服务器用POST。
空src属性的图片的行为可能跟你预期的不同。它有两种形式:
<img src="">
var img = new Image(); img.src = "";
两种形式都会产生相同的效果:浏览器向您的服务器发出另外一个请求
### 3.1 减少Cookie大小
http cookie的使用有多种缘由,好比受权和个性化。cookie的信息经过http头部在浏览器和服务器端交换。尽量减少cookie的大小来下降响应时间。
当浏览器发出静态图像请求并将cookie与请求一块儿发送时,服务器对这些cookie没有任何用处。因此他们只是没有充分理由建立网络流量。您应该确保使用无cookie请求请求静态组件。建立一个子域并在那里托管全部静态组件。
若是您的域名是www.example.org
,您能够托管您的静态组件static.example.org
。可是,若是您已经在顶级域上设置了cookie example.org
而不是www.example.org
,则全部请求都 static.example.org
将包含这些cookie。在这种状况下,您能够购买一个全新的域,在那里托管您的静态组件,并保持此域无cookie
在研究Yahoo!的性能时,咱们发现将样式表移动到文档HEAD会使页面看起来加载速度更快。这是由于将样式表放在HEAD中容许页面逐步呈现。
关注性能的前端工程师但愿页面被逐步渲染,这时由于,咱们但愿浏览器尽早渲染获取到的任何内容。这对大页面和网速慢的用户很重要。给用户视觉反馈,好比进度条的重要性已经被大量研究和记录。在咱们的状况中,HTML
页面就是进度条。当浏览器逐步加载页面头部,导航条,logo等等,这些都是给等待页面的用户的视觉反馈。这优化了总体用户体验。
把样式表放在文档底部的问题是它阻止了许多浏览器的逐步渲染,包括IE。这些浏览器阻止渲染来避免在样式更改时须要重绘页面元素。因此用户会卡在白屏。
CSS表达式是强大的(可能也是危险的)设置动态CSS属性的方法。IE5开始支持,IE8开始不同意使用。例如,背景颜色能够设置成每小时轮换:
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
表达式的问题在于它们的评估频率高于大多数人的预期。它们不只在页面呈现和调整大小时进行从新计算,并且在页面滚动时甚至在用户将鼠标移动到页面上时进行计算。在CSS表达式中添加计数器可让咱们跟踪CSS表达式的计算时间和频率。在页面上移动鼠标能够轻松计算超过10,000次。
<link>
而不是@import
以前的一个最佳原则是说CSS应该在顶部来容许逐步渲染。
在IE用@import
和把CSS放到页面底部行为一致,因此最好别用。
专有的AlphaImageLoader
过滤器旨在解决IE版本<7中的半透明真彩色PNG的问题。该过滤器的问题在于它在下载图像时阻止渲染并冻结浏览器。它还会增长内存消耗,而且每一个元素应用,而不是每一个图像,所以问题成倍增长。
最佳作法是放弃AlphaImageLoader
,改用PNG8来优雅降级。
脚本引发的问题是它们阻塞了并行下载。 HTTP1.1规范建议浏览器每一个域名下不要一次下载超过2个组件。若是你的图片分散在不一样服务器,那么你能并行下载多个图片。但当脚本在下载,浏览器不会再下载其它组件,即便在不一样域名下。
有些状况下把脚本移动到底部并不简单。好比,脚本中用了document.write
来插入内容,它就不能被移动到底部。另外有可能有做用域问题。但大多数状况,有方法能够解决这些问题。
一个替代建议是使用异步脚本。defer
属性代表脚本不包含document.write
,是提示浏览器继续渲染的线索。
在实际中使用外部文件一般会产生更快的页面,由于浏览器会缓存JavaScript和CSS文件。每次请求HTML文档时,都会下载HTML文档中内联的JavaScript和CSS。这减小了所需的HTTP请求数,但增长了HTML文档的大小。另外一方面,若是JavaScript和CSS位于浏览器缓存的外部文件中,则HTML文档的大小会减小,而不会增长HTTP请求的数量。
压缩就是删除代码中没必要要的字符来减少文件大小,从而提升加载速度。当代码压缩时,注释删除,不须要的空格(空白,换行,tab)也被删除。
在一个页面中两次包含相同的JavaScript文件会损害性能。这并不像你想象的那么不寻常。对美国十大顶级网站的评论显示,其中两个网站包含重复的脚本。两个主要因素会增长脚本在单个网页中重复的概率:团队规模和脚本数量。当它发生时,重复的脚本会经过建立没必要要的HTTP请求和浪费的JavaScript执行来损害性能。
发出没必要要的http请求发生在IE而不是Firefox。在IE,若是外部脚本引入两次且没有缓存,它会发出2个请求。即便脚本被缓存,刷新时也会发出额外请求。
除了增长http请求,时间被浪费在执行脚本屡次上。无论IE仍是Firefox都会执行屡次。
使用JavaScript访问DOM元素的速度很慢,所以为了得到响应更快的页面,您应该:
有时候页面看起来不那么响应(响应速度慢),是由于绑定到不一样元素的大量事件处理函数执行太屡次。这是为何使用_事件委托_是一种好方法。
另外,你没必要等到onload
事件来开始处理DOM树,DOMContentLoaded
更快。大多时候你须要的只是想访问的元素已在DOM树中,因此你没必要等到全部图片被下载。
pngcrush
或其它工具压缩png。jpegtran
或其它工具压缩jpeg。不要使用比您须要的更大的图像,由于您能够在HTML中设置宽度和高度。若是您须要, <img width="100" height="100" src="mycat.jpg" alt="My Cat" />
那么您的图像(mycat.jpg)应该是100x100px而不是缩小的500x500px图像。
favicon.ico
小且可缓存favicon.ico是在你服务器根路径的图片。邪恶的是即便你不关心它,浏览器仍然会请求它。因此最好不要响应404。另外因为在同一服务器,每次请求favicon.ico时也会带上cookie。这个图片还会影响下载顺序,好比在IE,若是你在onload
时下载额外的组件,fcvicon会在这些组件以前被下载。
怎么减轻favicon.ico的缺点?
此限制与iPhone不会缓存大于25K的组件这一事实有关。请注意,这是未压缩的大小。在这里减小组件大小很重要,由于单独使用gzip可能还不够。
将组件打包到多部分文档就像带有附件的电子邮件,它能够帮助您经过一个HTTP请求获取多个组件(请记住:HTTP请求很昂贵)。使用此技术时,首先检查用户代理是否支持它(iPhone不支持)。