前端优化的35条规则(一)
内容部分
1. 尽量减少HTTP请求数
用户访问页面,80%的响应时间花在前端,大部分时间用于下载组件(js/css/image/flash等),减少组件数就是减少渲染页面所需的http请求数,这是让页面更快的关键。
减少组件数的一个方法就是简化页面设计,保持富内容的页面且能减少http请求,有以下几个技术
- Combined files 合并文件,如合并js,合并css都能减少请求数。如果页面间脚本和样式差异很大,合并会更有挑战性。
- CSS Sprites 雪碧图可以将小图标和背景图像合并到一张图片上,通过
background-image
和background-position
来显示不同部分。 - Image maps 图像映射, 合并多个图片到一个图片,一般用于导航条等,由于定义坐标的枯燥和易错,一般不推荐使用
- Lnline images 使用
data:url scheme
来内联图片 减少请求数是为第一次访问页面的用户提高性能的最重要的指导。
2. 减少DNS查询
就像电话簿,你在浏览器地址栏输入网址,通过DNS查询得到网站真实IP。
DNS查询被缓存来提高性能。这种缓存可能发生在特定的缓存服务器(ISP/local area network维护),或者用户的计算机。DNS信息留存在操作系统DNS缓存中(在windows中就是 DNS Client Serve )。大多浏览器有自己的缓存,独立于操作系统缓存。只要浏览器在自己的缓存里有某条DNS记录,它就不会向操作系统发DNS解析请求。
IE默认缓存DNS记录30分钟,写在DnsCacheTimeout
注册表设置中。FireFox默认缓存1分钟,可以用network.dnsCacheExpiration
配置项设置。(Fasterfox把缓存时间改成了1小时 P.S. Fasterfox是FF的一个提速插件)
当客户端的DNS缓存是空的(包括浏览器的和操作系统的),DNS查找数等于页面上不同的主机名数,包括页面URL,图片,脚本文件,样式表,Flash对象等等组件中的主机名,减少不同的主机名就可以减少DNS查找。
减少DNS请求数可能会减少并行下载数。避免DNS查找减少响应时间,但减少并行下载数可能会增加响应时间。指导原则是组件可以分散在至少2个但不多于4个的不同域名。这是同时减少DNS查找和允许高并发下载的折中方案。
3. Avoid Redirects 避免重定向。
跳转用301或302状态码来达成。一个301响应http头的例子:
HTTP/1.1 301 Moved Permanently
Location: http://example.com/newuri
Content-Type: text/html
浏览器自动跳转到Location指定的路径。跳转所需的所有信息都在http头,所以http主体一般是空的。301 302响应一般不会被缓存,除非有额外的头部信息,比如Expires或Cache-Control指定要缓存。meta刷新标签或 JavaScript 也可以跳转,但如果真要跳转,3xx跳转更好,主要是保证返回按钮可用。
跳转显然拖慢响应速度。在跳转的页面被获取前浏览器没什么能渲染,没什么组件能下载。
最浪费的跳转之一发生在url尾部slash(/)缺失。比如http://astrology.yahoo.com/astrology
会301跳转到http://astrology.yahoo.com/astrology/
(注意添在尾部的斜线)在Apache中可以用Alias,mod_rewrite或者DirectorySlash指令来取消不必要的重定向。
重定向最常见的用途是把旧站点连接到新的站点,还可以连接同一站点的不同部分,针对用户的不同情况(浏览器类型,用户帐号类型等等)做一些处理。用重定向来连接两个网站是最简单的,只需要少量的额外代码。虽然在这些时候使用重定向减少了开发人员的开发复杂度,但降低了用户体验。一种替代方案是用Alias和mod_rewrite,前提是两个代码路径都在相同的服务器上。如果是因为域名变化而使用了重定向,就可以创建一条CNAME(创建一个指向另一个域名的DNS记录作为别名)结合Alias或者mod_rewrite指令。
4. Make Ajax Cacheable 让Ajax可缓存。
使用ajax的好处是可以向用户提供很快的反馈,因为它是向后台异步请求数据。但是,这些异步请求不保证用户等待的时间——异步不意味着瞬时。
提高ajax性能的最重要的方法是让响应被缓存,即在Add an Expires or a Cache-Control Header中讨论的 Expires 。其它方法是:
- gzip组件
- 减少DNS查找
- 压缩JS
- 避免跳转
- 设置ETags
5. Post-load Components 延迟加载组件。
看看你的页面然后问问自己,什么才是一开始渲染页面所必须的?其余内容都可以等会儿
JavaScript是分隔onload事件之前和之后的一个理想选择。例如,如果有JavaScript代码和支持拖放以及动画的库,这些都可以先等会儿,因为拖放元素是在页面最初渲染之后的。其它可以延迟加载的部分包括隐藏内容(在某个交互动作之后才出现的内容)和折叠的图片。
最好让性能目标符合其它web开发最佳实践,比如“渐进增强”。如果客户端支持JavaScript,可以提高用户体验,但必须确保页面在不支持JavaScript时也能正常工作。所以,在确定页面运行正常之后,可以用一些延迟加载脚本增强它,以支持一些拖放和动画之类的华丽效果。
6. Preload Components 预加载组件。
预加载看起来与延迟加载相反,但它的确有个不同的目标。通过预加载你可以利用浏览器的空闲时间来请求你将来会用到的组件。这样当用户访问下一个页面时,你会有更多的组件已经在缓存中,这样会极大加快页面加载。
有几种预加载类型:
- 无条件预加载:一旦onload触发,你立即获取另外的组件。比如谷歌会在主页这样加载搜索结果页面用到的雪碧图。
- 有条件预加载:基于用户动作,你推测用户下一步会去哪里并加载相应组件。
- 预期的预加载:在发布重新设计(的网站)前提前加载。在旧网页预加载新网页的部分组件,那么切换到新网页时就不会是没有任何缓存了。
7. Reduce the Number of DOM Elements 减少dom数。
一个复杂的页面意味着更多的内容要下载,以及更慢的dom访问。比如在有500dom数量的页面添加事件处理就和有5000dom数量的不同。
如果你的页面dom元素很多,那么意味着你可能需要删除无用的内容和标签来优化。
8. Split Components Across Domains 把组件分散到不同的域名。
把组件分散到不同的域名允许你最大化并行下载数。由于DNS查询的副作用,最佳的不同域名数是2-4。
9. Minimize the Number of iframes 最小化iframe的数量。
iframe允许html文档被插入到父文档。
<iframe>
优点:
- 帮助解决缓慢的第三方内容的加载,如广告和徽章
- 安全沙盒
- 并行下载脚本
<iframe>
缺点:
- 即使空的也消耗(资源和时间)
- 阻塞了页面的onload
- 非语义化(标签)
10. No 404s 不要404。
http请求是昂贵的,所以发出http请求但获得没用的响应(如404)是完全不必要的,并且会降低用户体验。
一些网站会有特别的404页面提高用户体验,但这仍然会浪费服务器资源。特别坏的是当链接指向外部js但却得到404结果。这样首先会降低(占用)并行下载数,其次浏览器可能会把404响应体当作js来解析,试图从里面找出可用的东西。