雅虎军规35条
?或许应该用更好的语义化标记。
YUI CSS utilities对布局有很大帮助:grids.css针对整体布局,fonts.css和reset.css可以用来去除浏览器的默认格式。这是个开始清理和思考标记的好机会,例如只在语义上有意义的时候使用
,而不是因为它能够渲染一个新行。
DOM元素的数量很容易测试,只需要在Firebug的控制台里输入:
document.getElementsByTagName('*').length
那么多少DOM元素才算是太多呢?可以参考其它类似的标记良好的页面,例如Yahoo!主页是一个相当繁忙的页面,但只有不到700个元素(HTML标签)。
8. 跨域分离组件
分离组件可以最大化并行下载,但要确保只用不超过2-4个域,因为存在DNS查找的代价。例如,可以把HTML和动态内容部署在www.example.org,而把静态组件分离到static1.example.org和static2.example.org。
9. 尽量少用iframe
用iframe可以把一个HTML文档插入到父文档里,重要的是明白iframe是如何工作的并高效地使用它。
iframe的优点:
引入缓慢的第三方内容,比如标志和广告
安全沙箱
并行下载脚本
iframe的缺点:
代价高昂,即使是空白的iframe
阻塞页面加载
非语义
10. 杜绝404
HTTP请求代价高昂,完全没有必要用一个HTTP请求去获取一个无用的响应(比如404 Not Found),只会拖慢用户体验而没有任何好处。
有些站点用的是有帮助的404——“你的意思是xxx?”,这样做有利于用户体验,,但也浪费了服务器资源(比如数据库等等)。最糟糕的是链接到的外部JavaScript有错误而且结果是404。首先,这种下载将阻塞并行下载。其次,浏览器会试图解析404响应体,因为它是JavaScript代码,需要找出其中可用的部分。
css部分:
11. 把样式表放在顶部
在Yahoo!研究性能的时候,我们发现把样式表放到文档的HEAD部分能让页面看起来加载地更快。这是因为把样式表放在head里能让页面逐步渲染。
关注性能的前端工程师想让页面逐步渲染。也就是说,我们想让浏览器尽快显示已有内容,这在页面上有一大堆内容或者用户网速很慢时显得尤为重要。给用户显示反馈(比如进度指标)的重要性已经被广泛研究过,并且被记录下来了。在我们的例子中,HTML页面就是进度指标!当浏览器逐渐加载页面头部,导航条,顶部logo等等内容的时候,这些都被正在等待页面加载的用户当作反馈,能够提高整体用户体验
在很多浏览器(包括IE)中,把样式表放在HTML文档底部都会阻止页面逐渐渲染。这些浏览器阻塞渲染过程,以避免因为样式变动而重绘页面元素,用户这时就只能盯着空白页面。
HTML官方文档 清楚地描述了样式表应该放在页面的HEAD里面:”Unlike A, [LINK] may only appear in the HEAD section of a document, although it may appear any number of times.”(不像a标签,link标签可能只出现在HEAD部分,虽然它能可以出现任意多次)。空白屏幕或者没有样式的falsh内容都是不可取的。理想方案就是遵循HTML官方文档,把样式表放在HTML文档的HEAD部分
12. 避免使用CSS表达式
用CSS表达式动态设置CSS属性,是一种强大又危险的方式。从IE5开始支持,但从IE8起就不推荐使用了。例如,可以用CSS表达式把背景颜色设置成按小时交替的:
background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
上面的代码中, expression 方法可以接受一个JavaScript表达式。CSS属性会被设置成表达式的计算结果。 expression 方法会被其它浏览器忽略,所以只有想办法实现跨浏览器的与IE一致的用户体验才有用。
表达式最大的问题是它们经常被重复计算,比我们想象的次数还要多。不仅仅是页面渲染和调整大小的时候,在页面被滚动,甚至用户在页面上移动鼠标时都会重新计算表达式。给CSS表达式添加一个计数器就可以追踪它重新计算的时间和频率,而在页面上动动鼠标就可以引发10000多次重新计算。
减少CSS表达式重新计算的一种方式就是用一次性表达式,即在表达式第一次计算后就把样式属性设置成一个明确的值,换掉表达式。如果必须要在页面的整个生命周期中动态设置样式属性,可以用事件处理器来代替CSS表达式。如果必须使用CSS表达式,要记得它们可能会被重复计算上千次,从而影响整个页面的性能。
13. 选择舍弃@import
前面提到了一个最佳实践:为了实现逐步渲染,CSS应该放在顶部。
在IE中用@import与在底部用效果一样,所以最好不要用它。
14. 避免使用滤镜
IE专有的AlphaImageLoader滤镜可以用来修复IE7之前的版本中半透明PNG图片的问题。在图片加载过程中,这个滤镜会阻塞渲染,卡住浏览器,还会增加内存消耗而且是被应用到每个元素的,而不是每个图片,所以会存在一大堆问题。
最好的方法是干脆不要用AlphaImageLoader,而优雅地降级到用在IE中支持性很好的PNG8图片来代替。如果非要用AlphaImageLoader,应该用下划线hack:_filter来避免影响IE7及更高版本的用户
js部分
15. 去除重复脚本
页面含有重复的脚本文件会影响性能,这可能和你想象的不一样。在对美国前10大web站点的评审中,发现只有2个站点含有重复脚本。两个主要原因增加了在单一页面中出现重复脚本的几率:团队大小和脚本数量。在这种情况下,重复脚本会创建不必要的HTTP请求,执行无用的JavaScript代码,而影响页面性能。
IE会产生不必要的HTTP请求,而Firefox不会。在IE中,如果一个不可缓存的外部脚本被页面引入了两次,它会在页面加载时产生两个HTTP请求。即使脚本是可缓存的,在用户重新加载页面时也会产生额外的HTTP请求。
除了产生没有意义的HTTP请求之外,多次对脚本求值也会浪费时间。因为无论脚本是否可缓存,在Firefox和IE中都会执行冗余的JavaScript代码。
避免不小心把相同脚本引入两次的一种方法就是在模版系统中实现脚本管理模块。典型的脚本引入方法就是在HTML页面中用SCRIPT标签:
PHP中一个可选方案是创建一个叫 insertScript 的函数:
除了防止相同脚本被多次引入,这个函数还可以解决脚本相关的其它问题,比如依赖性检查和给脚本文件名添加版本号来支持“永久”有效期HTTP头。
16. 尽量减少DOM访问
用JavaScript访问DOM元素是很慢的,所以,为了让页面反应更迅速,应该:
缓存已访问过的元素的索引
先“离线”更新节点,再把它们添到DOM树上
避免用JavaScript修复布局问题
17. 用智能的事件处理器
有时候感觉页面反映不够灵敏,是因为有太多频繁执行的事件处理器被添加到了DOM树的不同元素上,这就是推荐使用事件委托的原因。如果一个div里面有10个按钮,应该只给div容器添加一个事件处理器,而不是给每个按钮都添加一个。事件能够冒泡,所以可以捕获事件并得知哪个按钮是事件源。
不需要为了处理DOM树而等待onload事件,通常只要目标元素在DOM树中可访问即可,而不必等待所有的图片下载完成。可以考虑用 DOMContentLoaded 来代替onload事件,但为了让它在所有浏览器中都可用,可以用 YUI Event 工具,它有一个 onAvailable 方法。
18. 把脚本放在底部
脚本会阻塞并行下载,HTTP/1.1官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。
有时候,并不容易把脚本移动到底部。举个例子,如果脚本是用document.write插入到页面内容中的,就没办法再往下移了。还可能存在作用域问题,在多数情况下,这些问题都是可以解决的。
一个常见的建议是用推迟(deferred)脚本,有DEFER属性的脚本意味着不能含有document.write,并且提示浏览器告诉他们可以继续渲染。不幸的是,Firefox不支持DEFER属性。在IE中,脚本可能被推迟,但不尽如人意。如果脚本可以推迟,我们就可以把它放到页面底部,页面就可以更快地载入。
javascript, css部分
19. 把JavaScript和CSS放到外面
很多性能原则都是关于如何管理外部组件的,然而,在这些顾虑出现之前你应该问一个更基础的问题:应该把JavaScript和CSS放到外部文件中还是直接写在页面里?
实际上,用外部文件可以让页面更快,因为JavaScript和CSS文件会被缓存在浏览器。HTML文档中的行内JavaScript和CSS在每次请求该HTML文档的时候都会重新下载。这样做减少了所需的HTTP请求数,但增加了HTML文档的大小。另一方面,如果JavaScript和CSS在外部文件中,并且已经被浏览器缓存起来了,那么我们就成功地把HTML文档变小了,而且还没有增加HTTP请求数。
关键因素是,外部文件被缓存的频率和页面被请求数量之间的关系。尽管这个因素很难量化,但我们还是可以用各种各样的指标来衡量。如果用户的每个会话中都有多次页面访问,那么相同的脚本和样式表就可以被多个页面复用,缓存的外部文件就会带来巨大的好处。
很多站点在度量中都处于中等水平,对这些站点来说,一般最好的解决方案就是把JavaScript和CSS部署为外部文件。唯一的例外是主页上行内方式优先,例如 Yahoo!的首页 和 My Yahoo! 。在每个会话中访问量比较少的主页会发现行内JavaScript和CSS能让终端用户的响应时间更快。
对典型的站点来说,首页是众多访问量的开始,有很多技术可以对减少HTTP请求起到杠杆作用,就像用外部文件缓存的好处一样。这样的一种技术就是在首页用行内JavaScript和CSS,但在页面载入完成之后动态加载外部文件,这样后续的页面所需的外部文件就已经被放到浏览器的缓存里了。
20. 压缩JavaScript和CSS
压缩具体来说就是从代码中去除不必要的字符以减少大小,从而提升加载速度。代码最小化就是去掉所有注释和不必要的空白字符(空格,换行和tab)。在JavaScript中这样做能够提高响应性能,因为要下载的文件变小了。两个最常用的JavaScript代码压缩工具是JSMin和YUI Compressor,YUI compressor还可以压缩CSS。
混淆是一种可选的源码优化措施,要比压缩更复杂,所以混淆过程也更容易产生bug。在对美国前十的网站调查中,压缩可以缩小21%,而混淆能缩小25%。虽然混淆的缩小程度更高,但比压缩风险更大。
除了压缩外部脚本和样式,行内的