[TOC]

image.png

浏览器向服务器请求资源过程

  • 输入网址;
  • 浏览器查找域名的IP地址;
  • 浏览器给web服务器发送一个HTTP请求 ;
  • 网站服务的永久重定向响应 ;
  • 浏览器跟踪重定向地址知道了要访问的正确地址,所以它会发送另一个获取请求;
  • 服务器“处理”请求,服务器接收到获取请求,然后处理并返回一个响应;
  • 服务器发回一个HTML响应 ;
  • 浏览器开始渲染HTML,显示HTML
  • 浏览器发送请求,以获取嵌入在HTML中的对象,在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签,这时,浏览器会发送一个获取请求来重新获得这些文件,这些文件就包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取类似的过程,所以浏览器会在DNS中查找这些域名,发送请求,重定向等。

浏览器解析渲染流程
一、大致分为五步:

  1.解析HTML

  2.构建DOM树

  3.DOM树与CSS样式进行附着构造呈现树

  4.布局

  5.绘制

二、解析渲染过程
image.png
  1.DOM Tree:浏览器将HTML解析成树形的数据结构,构建一颗DOM树,同时进行第三步。

  2.CSS Rule Tree:浏览器将CSS解析成树形的数据结构,构建CSSOM tree,生成页面的样式表。

  3.Render Tree: 将DOM树和样式表,关联起来,构建一颗Render树(这一过程又称为Attachment)。每个DOM节点都有attach方法,接受样式信息,返回一个render对象(又名renderer)。这些render对象最终会被构建成一颗Render树。

  4.layout: 有了Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的CSS定义以及他们的从属关系,从而去计算出每个节点在屏幕中的位置。

  5.painting: 按照算出来的规则,调用每个节点paint方法,把它们绘制出来。

  6.reflow(回流or重排):当浏览器发现某个部分发生了点变化影响了布局,需要倒回去重新渲染,这个回退的过程叫 reflow。reflow 会从 这个 root frame 开始递归往下,依次计算所有的结点几何尺寸和位置。reflow 几乎是无法避免的。现在界面上流行的一些效果,比如树状目录的折叠、展开(实质上是元素的显示与隐藏)等,都将引起浏览器的 reflow。鼠标滑过、点击……只要这些行为引起了页面上某些元素的占位面积、定位方式、边距等属性的变化,都会引起它内部、周围甚至整个页面的重新渲染。通常我们都无法预估浏览器到底会 reflow 哪一部分的代码,它们都彼此相互影响着。要从第四步重新开始,更加耗费性能。

  7.repaint(重绘):改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸没有变,只需要重新走第五步。

浏览器从服务端拿到html文件后,首先开始解析html文件,构建DOM tree,并且同时构建Render Tree;
遇到js文件的话,阻塞DOM tree的构建;因为js可能会改变dom和css,因此浏览器会先解析script,避免浪费。
遇到css文件的话,先加载css然后构建CSSOM Tree,与此同时构建DOM Tree, 但是将阻塞Render Tree的构建。
如果将css文件放在底部,render tree在之前就已经构建完了,因此用户可能会看到无样式的页面,或者闪屏。
重排意味着重新计算节点的位置大小等信息,重新在草稿本上画了草图,所以一定会重绘。重绘不一定会重排,比如背景颜色改变
重排和重绘代价很高,所以浏览器并不会一有信息改变就去执行重排和重绘,而是会将多个可能的重排和重绘一次执行。
有两个css属性,display: none和visibility: hidden,前者会导致重排和重绘,后者会导致重绘。这是后者的优点,但缺点是此节点一直保存在内存中,占用资源。
————————————————
版权声明:本文为CSDN博主「Miofly」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40013817/article/details/103116933

前言

  • 重排、重绘、合成是什么?总的来说,它们都是浏览器渲染页面进程中的一个小小的环节,正是这些小环节按照一定的规则有条不紊的运作,才保证了我们能正常、顺畅地网上冲浪。
  • 本文主要介绍了重排、重绘、合成的基本概念、触发时机、影响范围以及其优化策略。
  • 我们首先来看一下,浏览器的渲染原理,看一下,它们分别担任了什么工作?

    一、浏览器渲染原理

    image.png
    结合上图,一个完整的渲染流程大致可总结为如下几个步骤:
  1. HTML被HTML解析器解析成DOM Tree
  2. CSS则被CSS解析器解析成CSSOM Tree
  3. DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)
  4. 布局,根据渲染树计算每个节点的几何信息生成布局树(Layout Tree)
  5. 对布局树进行分层,并生成分层树(Layer Tree)
  6. 为每个图层生成绘制列表
  7. 渲染绘制(Paint)。根据计算好的绘制列表信息绘制整个页面,并将其提交到合成线程
  8. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图,发送绘制图块命令 DrawQuad 给浏览器进程
  9. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上

    二、重排

  10. 定义:当通过JS或css改变了元素的宽度、高度等,修改了元素的几何位置属性,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。

  11. 触发时机和影响范围:DOM节点信息更改,触发重排时,这个DOM更改程度会决定周边DOM更改范围。

    • 全局范围:就是从根节点html开始对整个渲染树进行重新布局,例如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等。
    • 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局。

      三、重绘

  12. 定义:如果修改了元素的背景颜色,并没有引起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘。相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。

  13. 触发时机和影响范围:每一次的dom更改或者css几何属性更改,都会引起一次浏览器的重排/重绘过程,而如果是css的非几何属性更改,则只会引起重绘过程。所以说重排一定会引起重绘,而重绘不一定会引起重排,重绘的开销较小,重排的代价较高。

    四、合成

  14. 定义:合成是一种将页面的各个部分分离成层(Layer Tree),分别将它们栅格化,然后在称为“合成线程”的中组合为页面的技术。

  15. 触发时机和影响范围:在GUI渲染线程后执行,将GUI渲染线程生成的绘制列表转换为位图,然后发送绘制图块命令 DrawQuad 给浏览器进程,浏览器进程根据 DrawQuad 消息生成页面,将页面显示到显示器上
  16. 优点:我们使用了 CSS 的 transform 来实现动画效果,避开了重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。

    五、常见的触发重排、重绘的属性和方法

  17. 常见的触发重排、重绘的属性和方法

浏览器解析渲染页面过程 - 图4

  1. 全局范围重排、局部范围重排、重绘的影响范围示例

浏览器解析渲染页面过程 - 图5

六、优化策略

6.1 减少DOM操作

  1. 最小化DOM访问次数,尽量缓存访问DOM的样式信息,避免过度触发重排。
  2. 如果在一个局部方法中需要多次访问同一个dom,可以在第一次获取元素时用变量保存下来,减少遍历时间。
  3. 用事件委托来减少事件处理器的数量。
  4. 用querySelectorAll()替代getElementByXX()。
  • querySelectorAll():获取静态集合,通过函数获取元素之后,元素之后的改变并不会影响之前获取后存储到的变量。也就是获取到元素之后就和html中的这个元素没有关系了
  • getElementByXX():获取动态集合,通过函数获取元素之后,元素之后的改变还是会动态添加到已经获取的这个元素中。换句话说,通过这个方法获取到元素存储到变量的时候,以后每一次在Javascript函数中使用这个变量的时候都会再去访问一下这个变量对应的html元素。

    6.2 减少重排

  1. 放弃传统操作DOM的时代,基于vue/react开始数据影响视图模式。
  2. 避免设置大量的style内联属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性。
  3. 不要使用table布局,因为table中某个元素一旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。
  4. 尽量少使用display:none可以使用visibility:hidden代替,display:none会造成重排,visibility:hidden只会造成重绘。
  5. 使用resize事件时,做防抖和节流处理。
  6. 分离读写操作(现代的浏览器都有渲染队列的机制)
  • 分离读写减少重排的原理





  1. 缓存布局信息

注意:offsetTop、offsetLeft、offsetWidth、offsetHeight、clientTop、clientWidth、clientHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle…会刷新渲染队列。当下一行代码有这些时,即使下一行是修改样式,也会直接发生重排。

6.3 css及优化动画

  1. 少用css表达式
  2. 样式集中改变(批量处理) 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
  3. 可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小
  4. 动画实现的速度的选择:牺牲平滑度换取速度。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。
  5. 开启css3动画硬件加速(GPU加速)把渲染计算交给GPU。(能用transform做的就不要用其他的,因为transform可以开启硬件加速,而硬件加速可以规避重排。直接跳过重排、重绘,走合成进程)

    box.style.left=’100px’ //向右移动100px,一次重排
    box.style.ctransform=’translateX(200)’ //向右移动200px,不会引发重排

七、结束:

读到这里,重排、重绘、合成的概念,以及如何针对它们做前端的性能优化,大家有没有更清楚一点呢?如果文中有哪些地方写的不好、不对的地方,欢迎大家批评指正,感谢您的阅读,今天也是元气满满的一天,一起加油呦!

八、感谢

  1. https://blog.csdn.net/qq_38128179/article/details/101023305
  2. https://blog.csdn.net/qq_44182284/article/details/116997207
  3. https://zhuanlan.zhihu.com/p/106971491?ivk_sa=1024320u