前端性能优化

一个成功的网站,除了完备的功能外,优雅的用户体验以及良好的性能优化都是不可或缺的。本文暂且抛开功能和用户体验,单方面深入网页的性能优化。


我们都知道网站的加载时间的快慢在很大程度上决定了用户是否下次还会光临你的网站,用户的耐心是有限的。在页面还没来得及显示时,用户就已经不耐烦的关闭网站了,即使再好的用户体验都是徒劳的。

那么到底应该怎么加快页面的加载时间呢?以下是我在学习的过程中总结出的几点:


一、减少HTTP请求


减少http请求时性能准则中一颗闪耀的明星,这个话题比较复杂,所以我分以下三部分进行讨论:


1)理解并行连接

HTTP1.1协议很明确地限制了单个用户不能再同一时间保持2个以上的连接,但比较新的浏览器都突破了这个限制。现在很多浏览器支持4个并行的连接,有一少部分已经支持到6个了。那么问题就来了,假如一个站点有很多http请求,浏览器并不能一次性的全部请求完,而是分批次的请求,这样就会出现“延时”。


2)合并资源文件

将多个CSS文件和js文件合并成一个单独的文件,这也会在很大程度上减少http的请求,另外浏览器也可以缓存这些文件,以便在下次访问站点时不需要重新发送请求获取文件,直接从缓存中获取。


3)使用图片精灵

所谓的图片精灵(CSS sprite)其实就是把几张图片拼成一张图而已。它提供了一种把很多小图片拼成一张大一些图片从而在低并发的浏览器上达到快速传输并呈现内容的目的。目前大部分网站都会使用夸页面的图片精灵,这是一种有效减少http请求的办法。使用时只需用background-position属性进行定位。


二、使用CDN加速


所谓的CDN(Content Delivery Network),即“内容分发网络”。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度


三、避免空的src和href属性值


有时候可以看到这样的情景,在页面加载的过程中,一个有着空src属性的,img元素被javascript动态地赋值。这样做的问题是,在脚本执行之前元素就被浏览器渲染了(尤其是当你把脚本放到文档最后的时候)。所以浏览器依然会发起一个http请求,虽然它是一个空值。同样的问题也发生在href这个属性上。有些时候,开发员想用超链接来触发javascript的一个交互。这时问题就来了,当用户触发了“单击”操作,如果href是空的,那么浏览器就像服务器发送一个http请求,这虽然不影响加载时间,但是会对服务器产生不必要的流量和压力。解决办法一般是href=javascript:;


四、增加过期头


为所有的静态文件,如:图片、样式、脚本、flash等都加上过期头,假如为这些静态文件设置过期日期为往后的15天,如果用户第二次访问你的网站,浏览器就不会再次去请求这些已经缓存的静态文件,加载时间就会很短。一个典型的过期头一般是这样子的

Expires:Wed, 1Jan 2020 00:00:00 GMT


五、启用gzip压缩


HTTP1.1协议引入了Accept-Encoding这个功能,它可以表明HTTP请求的内容是被压缩过的,示例:

Accept-Encoding:gzip, deflate

Accept-Encoding规定了两种压缩方式。gzip是最长用的一种,因为它是显存的压缩比率最高的方法,大约可以减少70%以上的文件大小。启用压缩减少了文件的传输时间,节省带宽。一般应该压缩一切文字的内容,这意味着需要压缩htmlcss、脚本、json等文本内容。图片是不需要压缩的,因为它本身就是可压缩的格式文件。


六、把CSS放在头部


有一些浏览器为了减少重绘,它们会在CSS文件加载完成后渲染页面。如果样式文件放在页面的底部,那么这些浏览器就会等所有文件都加载完才去绘制页面。那么用户很有可有会在一段时间里看到的是白屏。不过目前可以说几乎所有的网站都会把样式文件放在头部。


七、把javascript放在尾部


脚本会阻塞并行加载。换句话说,当浏览器加载一个脚本时,它不会加载其他文件。如果脚本在头部,那它会阻止页面的渲染,并开始的时候用户就什么也看不到。

可以用script标签上的defer属性通知浏览器在加载脚本时也去加载其他文件。但这个做会有问题,首先ie的老版本并不支持这个属性,其次,用了defer属性后,脚本时不能使用document.write()了,虽然这不怎么常用。

那么把脚本放在最后,在body标签结束处,在本质上解决了脚本阻塞加载的问题,而且不需要用ready事件来保证所用的元素可用,因为当脚本执行时元素肯定是可用的。


八、避免使用CSS表达式


这个算是老生常谈的问题了,只有ie5-7支持css表达式,其他浏览器从未支持过。CSS表达式致命的一点是,它执行的频率远远超出想象,只要页面一滚动,它就会重复执行,甚至在鼠标移动的时候,它也会执行,这在效率以及性能上是很低的。


九、移出不使用的CSS语句


据我所知,目前绝大多数浏览器的样式引擎都是通过遍历所有的CSS规则来寻找匹配的元素。所以如果有很多没用的CSS语句,那它就会白白浪费样式引擎的时间。移除不使用的CS语句还会减少CSS文件的体积,让浏览器更快的加载它们,以节省带宽。


十、对JavaScriptCSS进行代码压缩


这条应该不需要多说了,基本上每个前端开发员都知道的一条准则。好处基本同上,减小体积,加速加载,节省带宽。压缩工具网上有很多,比较出名的有雅虎的YUI压缩工具,当然还有其他,这里不一一列举了。


十一、减少重绘


对于减少重绘,也分为三部分讨论:


1)规定图片的宽高

应该为每一个img元素设定宽高。当浏览器在生成布局数的时候,它会给每个元素留一个区域。如果不在一开始规定好img的宽高,那浏览器只好猜了,而且猜错的概率很大。当它把图片下载完后发现猜错了,它预留的区域大小不对,那只能重绘来纠正这个错误。可以通过定义宽和高来避免这次重绘。


2)不要用表格布局

有很多理由不用表格进行布局,只在需要显示表格类数据时使用表格。其中就是表格通常会导致页面的重绘,而且会在渲染完整个表格的时候才会绘制到屏幕上。浏览器是一行一行显示表格的,如果有一行的列宽或行高和之前的不一样,那之前绘好的行也必须重新绘制。如果我们只是在显示表格类数据时使用表格,那应该没什么问题。另外,表格布局也不利于seo优化。


3)不要重组DOM

重新排列DOM通常都会引发浏览器的重绘。通常浏览器对于DOM的渲染还是比较快的,因为html文件是浏览器第一时间要下载的文件。所以其他任何脚本增加或移出一个DOM元素都会造成浏览器的重绘,至少是重绘一部分。还有,移动DOM元素其实就是在一个地方删除一个,然后再另一个地方添加一个而已,比单纯地添加和删除还要糟糕。

对于DOM节点,能不操作最好,如果一定要操作DOM,那就是用产生重绘最少的方式。


讲了那么多,是时候总结一下加快页面加载时间的技巧了:

1、把CSS放到头部

2、把javascript放到body标签尾部

3、定义图片的宽和高

4、用以下方法减少http请求

a) 合并资源文件

b) 使用图片精灵

5、避免空的srchref属性

6、启用gzip压缩

7、摒弃CSS表达式

8、使用高校的CSS选择器

9、使用外链的CSSJavaScript

10、减少重绘


当然加快页面的加载速度并不仅限于所列举的这些技巧,或许每个前端开发者都有一套自己的优化方案,但不管怎么样,我们在开发的过程中就需要注意页面的优化,使用已知的技巧,开发高性能的web