性能

最后更新于:2022-04-01 02:00:53

[TOC] 当我们持续把web的能力发挥到极致的时候,让网页在最小开销或等待时间下可用依然是同样重要的问题。下面的章节说明如何优化网页使用户满意。 ### 优化CSS 和 Javascript传输 在生产环境传输CSS和Javascript,必须采用很多优化措施: * 遵循 [Yahoo 性能指南](http://developer.yahoo.com/performance/) * 使用 [smush.it](http://smush.it/) 对图片进行无损压缩优化。 还有,用 [YSlow](http://developer.yahoo.com/yslow/) 可以把你所有的图片自动压缩(【译者注】YSlow不仅仅提供性能优化工具,还详细说明了性能优化的34条规则,例如不要用CSS表达式、不要用空白的src或href、使用CDN、缓存AJAX响应、不要用过滤器、减少DOM元素数量等等)。 * 不要在HTML中写内联脚本 `<script>` 块。 它们会阻塞页面渲染操作,对页面加载时间带来破坏性的影响。 * 适当地设置缓存标题。 * 针对静态资源,考虑单独配置一个无cookie的子域。 * CSS 必须放在文档的 `<head>` 部分, Javascript 必须正好放在 `</body>` 标签的前面。 * CSS 和 JavaScript 都必须以最小化方式加载。大部分人会使用 [YUI 压缩器](http://developer.yahoo.com/yui/compressor/) 做这件事。 * CSS 和 JavaScript 都必须 [以gzip形式传输](http://code.google.com/speed/page-speed/docs/payload.html#GzipCompression)。 * CSS 必须串接在一起。显然,只有具备相同媒体类型(例如屏幕或打印)的文件才能合在一起。这里的总体目标是在加载页面的时候减少因为依赖关系而产生的HTTP连接数。 * JavaScript 必须串接在一起。虽然用一个AJAX脚本依赖性管理器(类似于 YUI 3 Loader)可能会比较理想,但实施起来还是挺复杂的。 在这里我还是想推荐单次下载站点用到的所有脚本。(当然了,适当的缓存也是必需的,这样可以让文件在合理的时间内尽可能保持在本地)。 * 串接和最小化通常发生在自动build的过程中,这时候要把代码打包用于发布或生产。有很多人用一些工具做这件事,例如 [Ant](http://ant.apache.org/) 或 [Maven](http://maven.apache.org/) 。 ### 优化 JavaScript 执行 在页面加载的时候,通常会有很多脚本等待执行,但你可以设定优先级。下面的顺序就是基于用户反馈设定的优先级: 1. 改变页面视觉习性的脚本绝对要首先执行。这包括任何的字体调整、盒子布局、或IE6 pngfix。 2. 页面内容初始化 3. 页面标题、顶部导航和页脚的初始化 4. 绑定事件处理器 5. 网页流量分析、Doubleclick,以及其他第三方脚本 ### 借力 CSS 精灵 CSS 精灵(Sprites) 基本上就是把一批图片资源合并成单个图片文件。然后每个部分用 CSS`background-position` 来展现。典型的 CSS 看起来是这样的 ~~~ a.expandbox { display:block; width: 75px; height: 15px; text-indent: -999px; overflow:hidden; background: url(../img/sprite.png) no-repeat -50px -5px; } ~~~ 接力 sprites 实现 :hover 悬停效果是很普遍的。这种情况下你会看到类似于这样的定义: ~~~ a.expandbox:hover { background-position: -50px -20px; } ~~~ 使用 sprites 可以减少页面大小,也减少了HTTP连接数,这会加速页面加载。 [在 css-tricks.com 上有更多总体性的技术和概述](http://css-tricks.com/css-sprites/)。尽可能地利用CSS 精灵总体来说是一项最佳实践。 除了主要的sprite之外,很多开发者还会使用一个垂直方向的sprite。这个垂直方向的sprite的宽度(以及高度)会**小于或等于100px**,包含了通常一个挨着一个的图标,诸如列表元素的着重号或对应功能的链接和按钮。Yahoo 就用到了一些,[例如这个](http://l.yimg.com/a/i/ww/sp/pa-icons3.gif)。 有个注意事项就是别把sprite弄得太大,不管是高还是宽超过1000px都会导致用掉大量内存。你可以学习一下 [使用sprite的时机及内存占用](http://blog.vlad1.com/2009/06/22/to-sprite-or-not-to-sprite/),如果需要了解更多关于创建sprite的总体性提示和技巧,请参阅 [Mozilla 开发博客](http://blog.mozilla.com/webdev/2009/03/27/css-spriting-tips/)。 ### 图片格式 你应该会用到四种主要的图片格式,细节如下: 1. **JPEG.** - 这种格式涵盖了所有基于摄影的图片,例如主页和目录页推销广告图片,或任何颜色数很高的图片。 2. **PNG24.** - 这种格式在Photoshop里用起来很方便,它输出高颜色数图片,并完全支持像素级的渐变透明度。相对来说,它是相当重量级的格式,达到KB级大小。它也是IE6唯一需要执行pngfix的格式。在那种情况下,本公司推荐使用 [DD_belatedPNG 脚本](http://www.dillerdesign.com/experiment/DD_belatedPNG/) (这是一个 pngfix ,它能修正 PNG24 在 IE6 里冒出灰色或浅蓝色背景的问题。它们并不总是和 `background-position` 兼容)。 在很多情况下,你可以使用GIF替代PNG24作为对IE6的应变方案。这在需要用PNG24做sprite的情况下尤其适用。所有的 pngfixes 都会特别慢而且开销巨大,所以最好不要用它们。 3. **PNG8.** - 在256色中可以抓取到如此多样的颜色,所以用JPG之前尝试一下PNG是值得的。而且,PNG比GIF有更高的可压缩度(使用类似 pngcrush 和 pngquant的工具)。这种格式支持在几乎所有浏览器中实现渐变透明度,但在IE6中那些半透明像素会显示为100%透明。不过在很多情况下这也够用了。它也无需运行pngfix脚本,所以对于速度是优化的。 Photoshop 无法正确输出这些半透明文件,但是Fireworks 可以。更多细节请参阅:[http://www.sitepoint.com/png8-the-clear-winner/](http://www.sitepoint.com/png8-the-clear-winner/) 4. **透明 GIF 89a.** - GIF 89a 提供透明度的灵活性和广泛的浏览器支持,但也有限制,它不支持渐变透明度和超过256的色深。就我们的经验而言,64的色深就可以提供质量很好的缩略图,并保持相对小的文件大小。 所有低颜色数图片,例如图表或主题图形应该用PNG8格式制作,因为它是这四种格式中具有最高文件大小效率的。PNG8是我们对于大部分网站图形的主要推荐方案。 关于PNG格式、浏览器支持以及各种格式优缺点的详细信息可以在 [这篇优秀的文章](http://calendar.perfplanet.com/2010/png-that-works/) 中找到。 如需进一步优化所有这些格式,从 [Yahoo的 Smush.It](http://smush.it/) 查看图片可以发现缩小它们的办法。 ### 缓存 对于静态内容,浏览器应该把文件在本地缓存,在合理的前提下,保留尽可能长的时间。应该较长远期缓存的内容包括: * CSS 和 JavaScript * 产品图片 * 主题图形 * favicon.ico * flash .swf's * 优惠信息图片(可能缓存时间会略短) 为了最佳缓存效果,利用http头部的Expires。下面是一个远期的Expires头,它告诉浏览器这个响应在2015年5月15日之前都无需更新: ~~~ Expires: Thu, 15 Apr 2015 20:00:00 GMT ~~~ 如果你的服务器是Apache,可以使用 `ExpiresDefault` 指令设置相对当前日期的失效日期。下面的例子设置失效日期为请求时间的一年之后: ~~~ ExpiresDefault "access plus 1 year" ~~~ http头部的 Expires 必须设为据现在一个月到一年(远期)之间的值。缓存只适用于那个指定的URL,所以文件名或任何资源的改变都会产生一个新的拷贝。很多开发者使用build过程来给它们的资源增加一个版本号或时间戳。每个随后的build会开始一个全新的缓存版本,让你在使用远期缓存日期时无需担心。 [Google 的这篇文章里有更多关于浏览器缓存的细节信息](http://code.google.com/speed/page-speed/docs/caching.html#LeverageBrowserCaching)。 ### 把资源文件跨域分片[◊](http://coderlmn.github.io/code-standards/#_shard_resources_across_domains "Permalink") 静态内容当然应该由不同于HTML所在服务器的另一个域提供访问。这是优化的方案,这样 [对所有静态内容的请求就无需额外的cookies头](http://developer.yahoo.com/performance/rules.html#cookie_free)。而且为整个域编写缓存规则也就容易得多了。(同时,当前域的任何子域会继承当前域的cookies,所以使用全新的域是值得的)。 不过,对于足够多的资源(特别是图片),请求数的增加足以让页面加载变慢。很多浏览器对于他们从每个域能并发下载的资源数有比较低的限制。(在IE6和IE7,这个数字仅仅是2)。在这种情况下,我们可以把资源存放在多个子域,例如: * static1.otherdomain.com * static2.otherdomain.com * static3.otherdomain.com [Google Speed 上更多有关域分片的信息](http://code.google.com/speed/page-speed/docs/rtt.html#ParallelizeDownloads) ### 避免用IFRAME Iframe 是能添加到指定页面的各种元素中上开销最大的一个。它们会阻塞页面让它无法触发onload事件,直到它们加载完成。有时候它们被其他机构用来处理追踪脚本。例如 Doubleclick floodlight 标签就是一个 iframe,管理员可以从他们的管理面板向里面增加追踪像素。在加入iFrame的任何情况下,它应该在window的onload事件被触发之后再动态加入到DOM中。 [更多细节请参阅 Yahoo 的性能站点。](http://developer.yahoo.com/performance/rules.html#iframes) ### 第三方集成 #### Omniture 我们推荐在页面加载完成(DOM ready 事件或 window 的 load事件)之后,再用 Javascript 把 Omniture Javascript 代码加入DOM中。通过使用这个技术,可以避免外部域脚本的依赖性,这种依赖性会减慢(并可能挂起)页面加载过程。 #### Flash 在所有情况下, Flash 的位置必须有备选的HTML内容,以使SEO值最大化。对于 XML 驱动的 Flash,备选 HTML 内容必须利用同一个 XML 文件,以确保数据的一致性。 所有替换内容必须使用 SWFObject ,但不应加入内联脚本标签。 SWFObject 的初始化必须在 DOM Ready 事件后触发。最小的播放器版本必须设置为最小 v9,以确保 AS3 兼容性。 ## 跨浏览器性能策略 谈到浏览器体验,有两个主要的事实: 1. 每个人都想要可能实现的响应性最好的体验。 2. 加到页面上的所有内容都会使它变慢。 那么,基于这两条人生真谛,我们需要通过什么样的步骤让大家满意呢? ### 与客户一起确定成功的性能指标 这些指标必须针对你的客户和项目来定制,在线框图布局阶段之前完成。这些目标从技术角度必须是合理的,也是可测试的。 **可能适用的一些目标** 1. 在支持的浏览器中,最慢的那个也必须在5秒钟之内完成从空白缓存到完全加载并初始化的过程。 2. 悬停状态(以及其他实时变化)必须在100毫秒内响应。 3. 动画必须流畅显示,其中跳变发生的时间 < 15%(包括所有浏览器)。 对于加载时间的目标,定义基准系统是很重要的。类似于 [PageTest](http://www.webpagetest.org/) 的工具是个好的选择。另外,目标也可以分开多个页面来定义,例如:访问量最大的两个目标网页(比如主页和支持页面)。 如果客户对于意向设计有比合理目标更激进的目标,就必须在整个项目决策委员会中统一期望值,并让项目组了解性能指标是最关键的。 ### 在设计阶段沟通性能的影响 **内部** 在 IA、IxD 和视觉设计阶段,前端工程师是负责沟通性能对于交互特性的影响或在目标浏览器上采用特定的视觉技术的角色。要给出设计师的限制条件:“如果我们使用Cufon,每个页面上用到定制字体的元素就不能超过10个。” **外部** 需要设定期望值: **并不是所有的浏览器都有相同的体验**。它们的表现不会彼此相同,指望它们的特性完全一样也不现实。在IE7的体验中放弃一些新的特性也许是合理的。会考虑被放弃的一些特性可能是: 阴影、过渡、圆角、透明度、渐变色。 **当沟通某件事的影响时** * 尽可能详细地明确影响程度:“这对页面加载有害” vs “这会在IE中增加2秒的页面加载时间“ * 如有可能,提供快捷的概念验证(Proof of Concept):”没有siFR的相似页面在2秒钟内加载,而用了siFR的用了8秒,而且在滚动时有延迟“ ### 遵循最佳实践进行开发 选择那些性能优化的库和插件。基于性能目标做出明智的架构决定。同时在可能的前提下尽量减少 DOM 操作,设计样式要让页面在加载和初始化的时候 [避免视觉变化](http://paulirish.com/2009/avoiding-the-fouc-v3/) 。 ### 在QA流程中评估性能 QA 团队也应该把性能相关的因素和视觉、功能和可用性问题放在一起来确定优先级。开发者和 QA 必须确定如何分配优先级。在 QA 过程中,成功的指标必须定期测试。 **测试用的工具** * [YSlow](http://developer.yahoo.com/yslow/), [Page Speed](http://code.google.com/speed/page-speed/), [Hammerhead](http://stevesouders.com/hammerhead/), [MSFast](http://msfast.myspace.com/), [PageTest](http://www.webpagetest.org/) **如果性能指标没有达到,有三个选择:** 1. 代码返工 - 重做架构,发现瓶颈,重构代码,优化指标让系统在浏览器里更快执行 2. 放弃该特性 - 只对较慢的浏览器关闭它 3. 重新设计用户交互方式 - 也许新的设计会有一招搞定问题的办法 我们认为,通过这个方法,在应对性能挑战的过程中,项目相关各方都有更好的机会统一期望,共同前进,并形成更加行之有效的工作流程。
';