网页的生成过程
HTML代码转化为DOMCSS代码转化成CSSOM(CSS Object Model)- 结合
DOM和CSSOM,生成一颗渲染树 (包含每个节点的视觉信息) - 生成布局 (
layout),即将所有渲染树的所有节点进行平面合成 - 将布局绘制(
paint)在屏幕上
最为耗时的在第四步和第五步
生成布局(flow)和绘制(paint),合称为渲染(render)
重排和重绘
网页生成的时候,至少会渲染一次。用户访问的过程中,还会不断重新渲染。
修改DOM、修改样式表、用户事件(鼠标悬停,页面滚动、输入框输入文字、改变窗口大小等)以上三种操作都会导致网页重新渲染。
重新渲染,就需要重新生成布局和重新绘制。前者叫做重排(reflow),后者叫做重绘(repaint)。重绘不一定需要重排,比如改变某个元素的颜色,就只会触发重绘, 因为布局没有变化,但是重排必然会导致重绘,比如改变某个元素的位置,就会同时触发重排和重绘,因为布局改变了。
提高网页性能,就是要降低重排和重绘的频率和成本,尽量少触发重新渲染
目前,浏览器已经很智能了,会尽量把所有变动集中在一起,排成一个队列,然后一次性执行,尽量避免多次重新渲染。
但是样式的写操作之后,有下面这些属性的读操作,会引发浏览器立即重新渲染
offsetTop/offsetLeft/offsetWidth/offsetHeightscrollTop/scrollLeft/scrollWidth/scrollHeightclientTop/clientLeft/clientWidth/clientHeightgetComputedStyle()
渲染的一般规则
- 样式表越简单,重排和重绘就越快
- 重排和重绘的
DOM元素层级越高,成本就越高 table元素的重排和重绘,要高于div元素
提高性能的九个技巧
DOM的多个读操作,或多个写操作,应该放在一起。不要两个读操作之间,加入一个写操作。- 如果某个样式是通过重排得到的,那么最好缓存结果,避免下次用到的时候,浏览器又要重排。
- 不要一条条地改变样式,而要通过
class或者csstext属性,一次性地改变样式 - 尽量使用离线
DOM,而不是真实的网面DOM,来改变元素样式。比如,操作Document Fragment对象,完成后再把这个对象加入DOM。再比如,使用cloneNode()方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点。 - 先将元素设为
display: none(需要1次重排和重绘),然后对这个节点进行100次操作,最后再恢复显示(需要1次重排和重绘)。这样一来,你就用两次重新渲染,取代了可能高达100次的重新渲染。 position属性为absolute或fixed的元素,重排的开销会比较小,因为不用考虑它对其他元素的影响- 只在必要的时候,才将元素的
display属性为可见,因为不可见的元素不影响重排和重绘。另外,visibility : hidden的元素只对重绘有影响,不影响重排。 - 使用虚拟
DOM的脚本库,比如React等。 - 使用
window.requestAnimationFrame()、window.requestIdleCallback()这两个方法调节重新渲染
刷新率
很多时候,密集的重新渲染是无法避免的,比如scroll事件的回调函数和网页动画。网页动画的每一帧都是一次重新渲染,每秒低于24帧的动画,人眼就能感受到停顿,一般的网页动画,需要达到30帧和60帧,才能比较流程,如果达到每秒 70帧以上,就会极其流畅,60帧意味着 一秒之内进行60次重绘,每次重新渲染的时间不能超过16.66毫秒。
一秒之间能够完成多少次重新渲染,这个指标就被成为刷新率FPS,如果想达到60帧的刷新率,就意味着JavaScript线程每个任务的耗时,必须少于16毫秒。一个解决办法是使用Web Worker,主线程只用于UI渲染,然后跟UI渲染不相干的任务,都放在Worker线程。
Chrome浏览器开发者工具的Timeline面板
Timeline面板提供两种查看方式:横条的是”事件模式”(Event Mode),显示重新渲染的各种事件所耗费的时间;竖条的是”帧模式”(Frame Mode),显示每一帧的时间耗费在哪里。
网页性能优化方案
使用 window.requestAnimationFrame(),它可以将某些代码放到下一次重新渲染时执行,让读操作和写操作分离,把所有的写操作放到下一次重新渲染。
使用 window.requestIdleCallback(),它指定只有当一帧的末尾有空闲时间,才会执行回调函数。
window.requestIdleCallback(()=>{}) 只有当前帧的运行时间小于16.66ms时,函数才会执行。否则,就推迟到下一帧,如果下一帧也没有空闲时间,就推迟到下下一帧,以此类推。
window.requestIdleCallback(()=>{},5000) 它还可以接受第二个参数,表示指定的毫秒数。如果在指定 的这段时间之内,每一帧都没有空闲时间,那么函数将会强制执行。





















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)