Yahoo前端优化性能规则

连接参考: https://developer.yahoo.com/performance/rules.htmljavascript

只有10%~20%的最终用户响应时间花在了下载HTML文档上,其他的80%~90%时间花在了下载页面中的全部组件上。
                                                        ——Steve Souders

规则1——减小HTTP请求(Minimize HTTP Requests)php

只有10%~20%的最终用户响应时间花在接收请求的HTML文档上,剩下的80%~90%时间都花在HTML文档所引用的全部组件(图片、脚本、样式表、Flash等)进行的HTTP请求上。所以,改善响应时间最简单的办法就是减小组件数量并由此减小HTTP请求数。减小组件数量一般会和产品设计的初衷相矛盾,所以,此处给出了一些技术:

   图片地图(Image Maps)联合多个图片到一个单独的图片中。下载图片大小的总和保持不变,可是,经过减小HTTP请求数的方式加速了页面。图片地图适用于导航栏或其余超连接中使用多个图片的情形。可是,在定义图片地图上的区域坐标时,若是采用手工方式很难完成且容易出错,并且除了矩形外几乎没法定义其余形状。

   CSS Sprites使用CSS background-image和background-position属性将多个图片联合成一个独立的图片来显示。它经过合并图片减小了HTTP请求,而且比图片地图更加灵活,同时也下降了图片的下载量。若是在页面中须要为背景、按钮、导航栏、连接等提供大量图片,CSS Sprites是一种优秀的解决方案。

   内联图片(Inline images)使用data: URL scheme模式将图片嵌入到HTML文档中。经过此模式嵌入图片,不须要任何额外的HTTP请求开销。可是,目前的主流浏览器(主要是IE)不支持此种方式。

   合并文件(Combined files)经过将全部JavaScript脚本合并到一个文件,全部CSS样式表合并到另外一个文件的方式来减小HTTP请求的数量。可是简单的合并一般会遇到模块化、页面变化等问题,须要根据页面引用脚本和样式表来具体分析以肯定具体的组合方式。

规则2——使用内容发布网络(Use a Content Delivery Network)html

用户同Web服务器的距离会对页面响应时间产生影响。网站最初一般将其全部服务器放在同一个地方,当用户群增长时,公司必须面对服务器放置地点再也不合适的事实。所以,有必要在多个地理位置不一样的服务器上部署内容。

   做为实现地理位置分离的第一步,不该当首先尝试使用分布式架构从新设计Web应用程序。这样的应用程序决定了从新设计将带来如同步会话状态、在服务器放置地点间复制数据库事务等复杂问题。从新设计会推迟甚至根本没法实现缩短用户和网站内容距离的愿望。

   若是应用程序Web服务器里用户更近,则一个HTTP请求的响应时间将被缩短;若是组件Web服务器离用户更近,则多个HTTP请求的响应时间将缩短。所以,与其从新开始设计应用程序,以便将应用程序Web服务器分散开,不如首先将组件Web服务器分散开。这不只能达到响应时间大幅减小的目的,还很容易实现。

   内容发布网络(CDN)是一组分布在多个不一样地理位置的Web服务器,用于更加有效的向用户发布内容。向特定用户发布内容的服务器基于对网络可用度的测量,例如,CDN可能选择网络阶跃数最小的服务器,或者具备最短响应时间的服务器。

   除了缩短响应时间外,CDN还能够带来其余优点,包括备份、扩展存储能力和进行缓存;同时,CDN还有助于缓和Web流量峰值的压力,如在获取天气或股市新闻、浏览体育或娱乐事件时。依赖CDN的一个缺点是网站的响应时间会受到其余网站——甚至多是竞争对手流量的影响;另外一个缺点是没法直接控制组件服务器所带来的问题。

  CDN用于发布静态内容(如图片、脚本、样式表、Flash)。提供动态HTML页面会引入特殊的存储要求——数据库链接、状态管理、验证、硬件和OS优化等,这些复杂性超过了CDN的范围。另外一方面,静态文件更容易存储并具备较少的依赖。

规则3——添加Expires头(Add an Expires or a Cache-Control Header)java

Web页面包含大量组件,而且数量在不断增加。页面的初访者会进行不少的HTTP请求,但经过一个长久的Expires头,可使这些组件被缓存下来,能够在后续的页面浏览中避免没必要要的HTTP请求。长久的Expires头最长用于图片,但应该将其用于全部组件上,包括脚本、样式表和Flash。

Web服务器使用Expires头告诉Web客户端它可使用一个组件的当前副本,知道指定时间为止。HTTP规范中简要的称该头为“在这一日期/时间以后,响应将被认为是无效的”。例如:

Expires: Thu, 15 Apr 2010 20:00:00 GMT

告诉浏览器该响应的有效性持续到2010年4月15日。

由于Expires头使用一个特定的时间,它要求服务端和客户端的时钟严格同步;另外,过时日期须要常常检查,一旦过时日期到了,须要在服务器中配置提供一个新的日期。因此,HTTP1.1引入了Cache-Control头来克服Exipres头的限制。Cache-Control使用max-age指令指定组件被缓存多久,它以秒为单位定义了一个更新窗。使用带有max-age的Cache-Control能够消除Expires的限制,但对于不支持HTTP1.1的应用,仍但愿使用Expires头。能够同时制定这两个响应头,若是二者同时出现时,HTTP规范规定max-age指令将重写Expires头。

当出现了Expires头时,直到过时时间为止一直会使用缓存的版本,浏览器不会检查任何更新,直到过了过时时间。为了确保用户可以获取组件的最新版本,须要在全部的HTML页面中修改组件的文件名。Yahoo在此使用了将版本号嵌入在组件的文件名中的方法。

规则4——压缩组件(Gzip Components)node

压缩组件经过减小HTTP请求产生的响应包的大小,从而下降传输时间的方式来提升性能。从HTTP1.1开始,Web客户端能够经过HTTP请求中的Accept-Encoding头来标识对压缩的支持:


Accept-Encoding: gzip, deflate

若是Web服务器看到请求中的这个头,就会使用客户端列出的方法中的一种来压缩响应。Web服务器经过响应中的Content-Encoding头来通知Web客户端:


Content-Encoding: gzip

目前许多网站一般会压缩HTML文档,脚本和样式表的压缩也是值得的(包括XML和JSON在内的任何文本响应理论上都值得被压缩)。可是,图片和PDF文件不该该被压缩,由于它们原本已经被压缩了。

压缩一般能将响应的数据量减小近70%,可是压缩一般状况下会带来服务端和客户端的CPU开销,要检测受益是否大于开销,须要综合考虑响应大小、链接的带宽和客户端也服务端直接的距离等因素。一般须要对大于1KB或2KB的文件进行压缩。

当浏览器经过代理来发送请求时,有可能出现浏览器指望接受的压缩后内容和实际接收到的不一致的状况。解决这一问题的方法是在Web服务器的响应中添加Vary头。Web服务器能够告诉代理根据一个或多个请求头来改变缓存的响应。因为压缩的决定是基于Accept-Encoding请求头的,所以须要在服务器的Vary响应头中包含Accept-Encoding:


Vary: Accept-Encoding

目前大约90%的经过浏览器进行的Internet通讯都须要使用gzip,使得服务端和客户端的对等性变得额外重要。不管是客户端仍是服务端发送错误,都会形成页面被破坏。避免错误的一种方式是采用“浏览器白名单”方式,即只为通过证明支持压缩的浏览器提供压缩内容,可是当代理缓存加进来之后,处理边缘情形浏览器将变得更加复杂。另外一种方式是使用Vary: *或Cache-Control: private头来禁用代理缓存。此种方式会为全部浏览器禁用代理缓存,从而增长带宽开销。如何平衡压缩和代理支持须要在加快响应时间、减少带宽开销和边缘情形浏览器缺陷之间进行权衡:

若是网站的用户不多,而且他们处于一个小圈子中,边缘情形浏览器不须要太多关注,能够压缩内容并使用Vary: Accept-Encoding。

若是更注重带宽开销,能够和前一种情形同样,压缩内容并使用Vary: Accept-Encoding。

若是网站拥有大量的、多变的用户群,可以应付较高的带宽开销,而且享有高质量的名声,须要压缩内容并使用Cache-Control: Private。(Google和Yahoo都使用这种方式)

规则5——将样式表放在顶部(Put Stylesheets at the Top)数据库

咱们都但愿页面可以逐步加载,也就是说,咱们但愿浏览器可以尽快显示内容。当浏览器逐步加载页面时,页头、导航栏、顶端logo等全部这些都会等待页面的用户提供视觉反馈,这改善了用户体验。将样式表放在底部,为避免当样式变化时重绘页面中的元素,浏览器会阻塞内容逐步呈现。

样式表在页面中的位置并不影响下载时间,可是会影响页面的呈现。根据HTML规范“和A不同,[LINK]只能出如今文档的HEAD节中,但其出现次数是任意的”。所以,问题的解决方式应该是遵循HTML规范,使用LINK标签将样式表放在文档的HEAD中。

规则6——将脚本放在底部(Put Scripts at the Bottom)浏览器

对响应时间影响最大的是页面中的组件数量,而脚本会阻塞组件的并行下载,带来性能上的问题。HTTP1.1规范建议浏览器从每一个主机名并行下载两个组件。若是一个Web页面平均将其组件分别放在两个主机名下,总体响应时间能够减小大约一半。咱们能够经过对浏览器默认设置的修改来增长每一个主机名并行下载组件的数量,也可使用CNAME(DNS别名)将组件分别放到多个主机名下。可是,增长并行下载数量一般会带来性能上的开销,过多的并行下载有时反而会下降性能。Yahoo!研究代表,使用两个主机名比使用一、4或10个主机名能带来更好的性能。

须要咱们注意的是,下载脚本时并行下载其实是被禁用的,即便此时使用了不一样的主机名,浏览器也不会启动其余下载。所以,若是将脚本放在顶部,脚本会阻塞后面内容的呈现,也会阻塞后面组件的下载。所以,放置脚本最好的地方是页面底部,这不会阻止页面内容呈现,并且页面中的可视组件能够尽早下载。

规则7——避免CSS表达式(Avoid CSS Expressions)缓存

CSS表达式是动态设置CSS属性的一种强大(而且危险)的方式。它从IE5之后的版本被支持,在IE8中已经被废弃。
表达式的问题在于对其进行的求值频率比人们指望的要高。它们不仅在呈现页面和大小改变时求值,当页面滚动,甚至用户鼠标在页面上移过期都要进行求值。

减小CSS表达式求值次数的一种方式是使用一次性表达式,若是CSS表达式必须被求值一次,能够在这一次中执行重写它自己。除此以外,还可使用事件处理器来为特定的事件提供所指望的动态行为。

规则8——使用外部JavaScript和CSS(Make JavaScript and CSS External)服务器

在现实环境中使用外部文件一般会产生较快的页面,由于JavaScript和CSS有机会被浏览器缓存起来。对于内联的状况,因为HTML文档一般不会被配置为能够进行缓存的,因此每次请求HTML文档都要下载JavaScript和CSS。因此,若是JavaScript和CSS在外部文件中,浏览器能够缓存它们,HTML文档的大小会被减小而没必要增长HTTP请求数量。

决定是否使用外部文件的关键在于被缓存的外部文件占请求的HTML文档数的比重。若是网站用户在每次会话中进行屡次页面访问,同时页面重用了多个脚本和样式表,使用外部文件时很好的选择。

对于大多数网站而言,难以精确度量以判断是否使用内联或外部文件,此时建议是使用外部文件的方式。对于这个问题的一个例外是网站主页,因为主页对于响应时间要求更高,所以更加倾向于内联而不是外部文件。

对于内联文件而言,因为没法利用浏览器缓存,所以给人感受依然比较低效。咱们能够经过加载后下载和动态内联的方式来使得网站主页既能够得到内联的优点,同时也能缓存外部文件。

规则9——减小DNS查找(Reduce DNS Lookups)网络

DNS对于网站来讲会带来开销。一般浏览器查找一个给定主机名的IP要花费20~120毫秒的时间。在DNS查找完成以前,浏览器不能今后主机下载任何东西。

DNS查找能够被缓存起来以提升性能,这种缓存能够发生在ISP或局域网中的一台特殊的缓存服务器上,同时,缓存也会发生在独立的用户机器上。在用户请求一个主机名后,DNS信息会留在操做系统的DNS缓存中,大多数浏览器也拥有本身的缓存,和操做系统缓存相分离。只要浏览器在其缓存中保留了DNS记录,就不会经过操做系统来请求这个记录。

当客户端浏览器和操做系统中DNS缓存同时为空时,DNS查询的数量等于页面中惟一主机名的数量,这些主机名包括了页面的URL、图片、脚本、样式表、Flash等。因此,减小惟一主机名数量,能够减小DNS查询数。

减小惟一主机名数量会潜在的减小页面中并行下载的数量。避免DNS查找下降了响应时间,但减小并行下载可能会增长响应时间。对于这种情形,建议将这些组件放在至少2个,但不要超过4个主机名下。

规则10——精简JavaScript和CSS(Minify JavaScript and CSS)
精简是从代码中移除没必要要的字符以减少其大小,进而改善加载时间。在代码被精简后,全部注释以及没必要要的空白字符(空格、换行和制表符)都将被移除。对于JavaScript而言,由于须要下载的文件大小减少了,能够改善响应时间。

混淆是能够应用在源代码上的另外一种优化方式。相比较于精简,混淆更加复杂,所以更容易产生bug。混淆能够更大程度上压缩源代码,可是也存在着必定的风险。

除了外部JavaScript外,内联在<script>和<style>块中的源代码也须要被精简。即便使用了gzip来压缩JavaScript和CSS,使用精简可以将代码大小再减小5%或者更多。

规则11——避免重定向(Avoid Redirects)

重定向用于将用户从一个URL路由到另外一个URL。重定向有不少种,其中301和302是最经常使用的两种。下面是一个301响应头的示例:


HTTP/1.1 301 Moved Permanently


Location: http://example.com/newuri


Content-Type: text/html

浏览器会自动将用户带到Location字段给出的URL。重定向所必需的全部信息都包含在这个头中,响应体一般是空的。无论叫什么名字,301或者302响应在实际中都不会被缓存,除非有附加的头(如Expires或Cache-Control等)要求它这么作。meta refresh标签和JavaScript也能够用于重定向,可是最好的技术是使用标准的3xx状态码,以保证后退按钮可以正常工做。

须要咱们记住的是重定向会使页面变慢。在用户和HTML文档间插入一个重定向后,在此HTML文档到达以前页面上不会描绘任何东西,任何组件也不会被下载。

有一种重定向最为浪费,发生的也很频繁,可是Web开发人员一般都没有意识到它,它发生在URL的结尾必须出现斜线(/)而没有出现的情形。例如访问地址http://astrology.yahoo.com/astrology将致使一个301响应包含重定向至http://astrology.yahoo.com/astrology/。当主机名后缺乏结尾斜线时不会发生重定向。在Apache中,咱们能够经过Alias指令或者mod_rewrite模块或者DirectorySlash指令来处理缺乏结尾斜线时的重定向问题。

从一个旧的站点连接到新的站点是使用重定向的另外一种常见场景。其余形式还包括将一个网站的不一样部分链接起来,以及基于一些条件(浏览器类型、用户账户类型等)来引导用户。使用重定向来链接两个网站很简单并且只须要不多的额外代码。可是,虽然重定向下降了开发的复杂性,也损害了用户体验,一般能够进行其余的选择:若是两个代码的路径在同一台服务器上,可使用Alias和mod_rewrite;若是域名因为重定向发生改变,可使用一个CNAME(一条DNS记录,用于建立一个域名指向另外一个域名的别名)让两个主机名指向相同的服务器,而后使用Alias和mod_rewrite。

规则12——移除重复脚本(Remove Duplicate Scripts)

在一个页面中两次保护同一个JavaScript文件会损伤性能。致使一个脚本重复的因素主要有两个——团队大小和脚本数量。

当重复脚本的现象发生时,将产生没必要要的HTTP请求和浪费执行JavaScript的时间。没必要要的HTTP请求会发生在IE中,而不会发生在Firefox中。在IE中,若是脚本被包含两次且没有被缓存,浏览器会在页面加载期间产生两个HTTP请求;即便脚本能够缓存,当用户从新加载页面时也会产生额外的HTTP请求。对JavaScript进行的多余的执行从而浪费时间的现象在IE和Firefox中都存在,与脚本是否被缓存无关。

避免意外包含同一脚本两次的一种方法是在你的模块系统中实现一个脚本管理模块。包含脚本的典型方式是在HTML页面中使用SCRIPT标签:


<script type=”text/javascript” src=”menu_1.0.17.js”></script>

另外一种选择是在PHP中建立一个函数:


<?php insertScript(“menu.js”) ?>

为了防止统一个脚本被重复添加屡次,insertScript函数须要添加处理脚本的依赖性和版本的功能。

规则13——配置Etag(Configure ETags)

实体标签(Entity Tag,ETag)是Web服务器和浏览器用于确认缓存组件的有效性的一种机制。ETag在HTTP1.1中引入,用于检测浏览器缓存中的组件与原始服务器上的组件是否匹配。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状态码,在此例中使响应减小12195字节。

GET /i/yahoo.gif HTTP/1.1


Host: us.yimg.com


f-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT


If-None-Match: “10c24bc-4ab-457e1c1f”


HTTP/1.1 304 Not Modified

ETag的问题在于,一般使用组件的某些属性来构造它,这些属性对于特定的、寄宿了网站的服务器来讲是惟一的。当浏览器从一台服务器上获取了原始组件以后又尝试向另外一台服务器来验证组件时,ETag是不匹配的。这种状况对于使用服务器集群来处理请求的网站来讲是很常见的一种状况。默认状况下,Apache和IIS向ETag中嵌入的数据都会大大下降有效性验证的成功率。

Apache1.3和2.x的ETag格式是inode-size-timestamp。文件系统使用inode来存储诸如文件类型、全部者、组和访问模式等信息。尽管在多台服务器上一个给定的文件可能位于相同的目录、具备相同的文件大小、权限、时间戳等,从一台服务器到另外一台服务器,器inode仍然是不一样的。
IIS5.0和6.0在ETag上有着相似的问题。IIS上ETag的格式是Filetimestamp:ChangeNumber。ChangeNumber适用于跟踪IIS配置变化的计数器。对于一个网站背后的全部IIS服务器来讲,ChangeNumber不大可能相同。
最

终的结果是,对于彻底相同的组件,从一台服务器到另外一台,Apache和IIS产生的ETag是不会匹配的。若是ETag不匹配,用户就不会按照ETag的设计计划那样接收到更小更快的304响应;相反,它们会收到普通的200响应以及组件的全部数据。若是只在一台服务器上部署网站,这一般不会产生问题;但若是使用了服务器集群,同时使用Apache或者IIS进行默认的ETag配置,用户响应将变慢,服务器负载将变高,将消耗更多的带宽,同时代理缓存的效率也会降低。即便组件具备长久的Expires头,一旦用户单击了Reload或Refresh按钮,依然会产生条件GET请求。
若是组件必须经过最新修改日期以外的一些东西来进行验证,则ETag是一种强大的方法;若是无须自定义ETag,则最好将其移除。Last-Modified头基于组件的时间戳进行验证,能够提供彻底等价的信息,并且移除ETag能够减小响应和后续请求的HTTP头的大小。在Apache中,只要向Apache配置文件中简单地添加下面一行配置就能移除ETag:
FileETag none

规则14——使Ajax可缓存(Make Ajax Cacheable)

Ajax的一个最重要的优势就是向用户提供即时反馈,由于它异步的从后台Web服务器请求信息。可是,使用Ajax并不保证用户不会等到异步的JavaScript和XML返回响应。在不少应用程序中,用户是否须要等待取决于如何使用Ajax。用户是否须要等待的关键因素在于Ajax请求是主动的仍是被动的。主动请求是基于用户的当前操做而发起的,被动请求则是为了未来使用而预先发起的。咱们须要注意的是,“异步”并无暗示“实时”。

为了提高性能,最重要的是优化Ajax响应。而改善这些主动Ajax请求的最重要的方式就是使响应可缓存。如同在“添加Expires头”中讨论的,一些其余规则也适用于Ajax,包括:压缩组件、减小DNS查找、精简JavaScript、避免重定向、配置Etag。
相关文章
相关标签/搜索