浏览器向服务器请求资源过程
- 输入网址;
- 浏览器查找域名的IP地址;
- 浏览器给web服务器发送一个HTTP请求 ;
- 网站服务的永久重定向响应 ;
- 浏览器跟踪重定向地址知道了要访问的正确地址,所以它会发送另一个获取请求;
- 服务器“处理”请求,服务器接收到获取请求,然后处理并返回一个响应;
- 服务器发回一个HTML响应 ;
- 浏览器开始渲染HTML,显示HTML
- 浏览器发送请求,以获取嵌入在HTML中的对象,在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签,这时,浏览器会发送一个获取请求来重新获得这些文件,这些文件就包括CSS/JS/图片等资源,这些资源的地址都要经历一个和HTML读取类似的过程,所以浏览器会在DNS中查找这些域名,发送请求,重定向等。
浏览器解析渲染流程
一、大致分为五步:
1.解析HTML
2.构建DOM树
3.DOM树与CSS样式进行附着构造呈现树
4.布局
5.绘制
二、解析渲染过程
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
前言
- 重排、重绘、合成是什么?总的来说,它们都是浏览器渲染页面进程中的一个小小的环节,正是这些小环节按照一定的规则有条不紊的运作,才保证了我们能正常、顺畅地网上冲浪。
- 本文主要介绍了重排、重绘、合成的基本概念、触发时机、影响范围以及其优化策略。
- 我们首先来看一下,浏览器的渲染原理,看一下,它们分别担任了什么工作?
一、浏览器渲染原理
结合上图,一个完整的渲染流程大致可总结为如下几个步骤:
- HTML被HTML解析器解析成DOM Tree
- CSS则被CSS解析器解析成CSSOM Tree
- DOM Tree和CSSOM Tree解析完成后,被附加到一起,形成渲染树(Render Tree)
- 布局,根据渲染树计算每个节点的几何信息生成布局树(Layout Tree)
- 对布局树进行分层,并生成分层树(Layer Tree)
- 为每个图层生成绘制列表
- 渲染绘制(Paint)。根据计算好的绘制列表信息绘制整个页面,并将其提交到合成线程
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图,发送绘制图块命令 DrawQuad 给浏览器进程
浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上
二、重排
定义:当通过JS或css改变了元素的宽度、高度等,修改了元素的几何位置属性,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。
触发时机和影响范围:DOM节点信息更改,触发重排时,这个DOM更改程度会决定周边DOM更改范围。
定义:如果修改了元素的背景颜色,并没有引起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘。相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
触发时机和影响范围:每一次的dom更改或者css几何属性更改,都会引起一次浏览器的重排/重绘过程,而如果是css的非几何属性更改,则只会引起重绘过程。所以说重排一定会引起重绘,而重绘不一定会引起重排,重绘的开销较小,重排的代价较高。
四、合成
定义:合成是一种将页面的各个部分分离成层(Layer Tree),分别将它们栅格化,然后在称为“合成线程”的中组合为页面的技术。
- 触发时机和影响范围:在GUI渲染线程后执行,将GUI渲染线程生成的绘制列表转换为位图,然后发送绘制图块命令 DrawQuad 给浏览器进程,浏览器进程根据 DrawQuad 消息生成页面,将页面显示到显示器上
优点:我们使用了 CSS 的 transform 来实现动画效果,避开了重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。
五、常见的触发重排、重绘的属性和方法
常见的触发重排、重绘的属性和方法
- 全局范围重排、局部范围重排、重绘的影响范围示例
六、优化策略
6.1 减少DOM操作
- 最小化DOM访问次数,尽量缓存访问DOM的样式信息,避免过度触发重排。
- 如果在一个局部方法中需要多次访问同一个dom,可以在第一次获取元素时用变量保存下来,减少遍历时间。
- 用事件委托来减少事件处理器的数量。
- 用querySelectorAll()替代getElementByXX()。
- querySelectorAll():获取静态集合,通过函数获取元素之后,元素之后的改变并不会影响之前获取后存储到的变量。也就是获取到元素之后就和html中的这个元素没有关系了
- getElementByXX():获取动态集合,通过函数获取元素之后,元素之后的改变还是会动态添加到已经获取的这个元素中。换句话说,通过这个方法获取到元素存储到变量的时候,以后每一次在Javascript函数中使用这个变量的时候都会再去访问一下这个变量对应的html元素。
6.2 减少重排
- 放弃传统操作DOM的时代,基于vue/react开始数据影响视图模式。
- 避免设置大量的style内联属性,因为通过设置style属性改变结点样式的话,每一次设置都会触发一次reflow,所以最好是使用class属性。
- 不要使用table布局,因为table中某个元素一旦触发了reflow,那么整个table的元素都会触发reflow。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。
- 尽量少使用display:none可以使用visibility:hidden代替,display:none会造成重排,visibility:hidden只会造成重绘。
- 使用resize事件时,做防抖和节流处理。
- 分离读写操作(现代的浏览器都有渲染队列的机制)
- 分离读写减少重排的原理
- 缓存布局信息
注意:offsetTop、offsetLeft、offsetWidth、offsetHeight、clientTop、clientWidth、clientHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle…会刷新渲染队列。当下一行代码有这些时,即使下一行是修改样式,也会直接发生重排。
6.3 css及优化动画
- 少用css表达式
- 样式集中改变(批量处理) 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
- 可以把动画效果应用到position属性为absolute或fixed的元素上,这样对其他元素影响较小
- 动画实现的速度的选择:牺牲平滑度换取速度。比如实现一个动画,以1个像素为单位移动这样最平滑,但是reflow就会过于频繁,大量消耗CPU资源,如果以3个像素为单位移动则会好很多。
开启css3动画硬件加速(GPU加速)把渲染计算交给GPU。(能用transform做的就不要用其他的,因为transform可以开启硬件加速,而硬件加速可以规避重排。直接跳过重排、重绘,走合成进程)
box.style.left=’100px’ //向右移动100px,一次重排
box.style.ctransform=’translateX(200)’ //向右移动200px,不会引发重排
七、结束:
读到这里,重排、重绘、合成的概念,以及如何针对它们做前端的性能优化,大家有没有更清楚一点呢?如果文中有哪些地方写的不好、不对的地方,欢迎大家批评指正,感谢您的阅读,今天也是元气满满的一天,一起加油呦!