最近参加了IMWEB前端技术沙龙活动,有幸能站到讲台上,将性能方面的经验与大家分享。现将“再议减少HTTP请求”部分简单摘剪成文。
前言:
关于web性能,有两个著名论断:
- 0.1-0.2s 用户认为是即时的;1-5s 用户觉得自己能与信息流畅地交互;5-10s 用户开始转移注意力——Robert Miller
- 用户所接受的数据,有80~90%的时间都耗在前端上——Steve Souders
前者说明,loading图(以下简称菊花)是必要的。人处于“开始转移注意力”时,这朵菊花就开始挽留你躁动的心。但web工程师的一个使命,就是通过提升性能,不让用户看到菊花。菊花要有,但不能常有,真是一朵磨人的小妖精…
后者说明,资源的加载和渲染可以大做文章。因为一个html文件,几乎是所有资源的承载器,哪些优先加载,怎样加载,都是前端工程师可以控制的。
再议减少HTTP请求:
“尽量减少HTTP请求,减少DNS查找”这是Yslow写在最前面的两条规则。而放之实际,可能会遇到挑战。为何?因为我们完成了“降低请求数”的目标,但可能损失了其他方面的指标。
a. 没有浏览器缓存
减少HTTP请求,很常用的做法就是把js和css资源inline到html里。这样的做法,自然没有浏览器缓存,重复加载时连静态资源也必须加载。也许有人又说,我可以把整个html文件都缓存啊!的确可以,但以web开发的更新速度,html文件一般都不设或设置很短时间(5 min?)缓存。另外在web2.0时代里,html缓存会带来不必要的问题。比如登录前后,页面资源展示不一样,那么我们就得慎用html缓存。
b. 没有cdn缓存
这个很好理解,任何的内联资源,由于依赖于html,都必须从源服务器而不是cdn服务器返回。
c. 不能按需加载
为了按需加载,前端工程师可谓想法各异,天马行空。比如图片的lazyload技术,异步加载js脚本,而inline的方式恰恰将一切想法摁回脑中。
d. 浏览器预解析DNS失效
现代浏览器有预解析DNS技术。简单来说,就是页面下载到浏览器时,先扫描一遍,在这时发现域名并预解析DNS。这样的前置解析跟dom渲染等操作同步执行,诚然会使浏览器更快。但如果你的html页面因为内联了太多内容(base64图片),大于5M时,浏览器的预解析DNS将会失效。
最佳实践
因而,我们时常像那只捡芝麻丢西瓜的熊。如此平衡这两者呢,业界给我们两个很好的案例。
Demo1 必应
- 首次内联CSS与JS
- 将资源取出,并保存在localStorage中
- 资源名(版本)保存在cookie中
- 后续请求中,服务器检查对应的cookie
- 根据cookie的值,只嵌入新的脚本
- 加载时,从localStorage里载入资源
Demo2 百度(移动端)
- 首次将静态资源打包,用jsonp统一返回
- 将资源解析并保存在localStorage中
- 再次访问时检查localStorage中资源情况
- 如有缺失再发请求获取资源
必应的做法确保了首次的http请求最少,后续充分发挥增量更新(当然粒度还是文件)的优势提高性能,但缺点是cookie并不可靠。百度则是把首次静态资源的http请求降低到一次,非常暴力的把全部css,js打包成字符串,以jsonp返回。宁愿用str转obj的解析时间去换取加载时间。而随V8引擎的强大,这点解析的时间也将越来越不值得提起。总而言之,这两个Demo都把http请求尽可能的降低,而后都利用了本地存储去获得资源。
我有时候会想起那把由无名的铁匠用三个小时粗制而成的小李飞刀。
你得对技术怀敬畏之心。因为那些谁都懂的技术,在某些人的手里,还真能变出花儿来。