前端性能优化
影响网页性能的因素
1、HTML 的解析和渲染(参见文档 《浏览器解析渲染HTML页面的过程》)
2、服务端处理的速度(负载均衡,缓存策略)
3、客户端带宽(网络状况)
我们要对网页的性能进行统计分析,首先应当确定哪些因素会对网页的性能带来影响。一般来说,前端HTML文档的结构是否合理,外部资源是否进行了压缩合并,静态内容是否使用了CDN加速,服务端是否配置了负载均衡,是否采取了缓存策略,以及客户端带宽状况等,都会对网页的性能造成影响。
前端在这方面可以做到的有两方面,页面级别的优化,比如减少 Http 请求次数、加快资源的加载速度;二是代码级别的优化,页面重新渲染一次会经过浏览器的重排(reflow
)和重绘(repaint
),这两部操作是非常耗时的。
页面级别优化
1. 减少 HTTP请求数
减少 http 请求次数的主要方法:
- 设置 HTTP缓存
http 缓存是 web 性能优化中非常重要的一种手段,把一些常用资源在首次加载时缓存到浏览器本地,再次加载时可大大减少请求次数,缓存的资源越多,性能当然越好。
缓存的规则主要有两种,强制缓存和对比协商缓存,详情见这里,两种缓存分别通过Http报文头部不同的字段进行控制。
- 资源合并压缩
CSS、 Javascript、Image 都可以用相应的工具(Webpack
)进行压缩,压缩后往往能省下不少空间。
- CSS Sprites
合并 CSS图片,减少请求数的又一个好办法。
- 懒加载
这条策略实际上并不一定能减少 HTTP请求数,但是却能在某些条件下或者页面刚加载时减少 HTTP请求数。
2. 把 js 脚本置底加载,css 放在 head 中
js 脚本是很容易形成阻塞,导致资源加载停滞,为了避免这种情况,先加载其他资源,最后加载脚本
页面渲染过程还要经历重绘重排,这样做是避免会出现 DOM 加载完之后却没有样式的情况。
3. 动态加载 js 模块
代码级别优化
DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 DOM元素或者对 DOM集合进行操作。
而修改 DOM 会引起网页的重新渲染。
重新渲染,就需要重新生成布局和重新绘制(颜色、背景等)。前者叫做"重排"(reflow),后者叫做"重绘"(repaint)。
提高网页性能,就是要降低"重排"和"重绘"的频率和成本,尽量少触发重新渲染。
一般的规则是:
样式表越简单,重排和重绘就越快。
重排和重绘的DOM元素层级越高,成本就越高。
table元素的重排和重绘成本,要高于div元素
提高性能的九个技巧
第一条,DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
第二条,如果某个样式是通过重排得到的,那么最好缓存结果。避免下一次用到的时候,浏览器又要重排。
第三条,不要一条条地改变样式,而要通过改变class,或者csstext属性,一次性地改变样式。
// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // good el.className += " theclassname"; // good el.style.cssText += "; left: " + left + "px; top: " + top + "px;";
第四条,尽量使用离线DOM,而不是真实的网面DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用 cloneNode() 方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。
第五条,先将元素设为display: none
(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。
第六条,position属性为absolute
或fixed
的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响。
第七条,只在必要的时候,才将元素的display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden
的元素只对重绘有影响,不影响重排。
第八条,使用虚拟DOM的脚本库,比如React等。
第九条,使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染。
参考地址:
https://segmentfault.com/a/1190000016529612
http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html