DOM渲染过程
面试题
DOM的渲染时机与渲染进程
渲染进程由五个线程组成
- JS引擎线程
JS负责执行脚本,是单线程执行;由于脚本会对DOM进行修改,假如一个线程添加DOM,一个线程删除DOM。
- GUI渲染线程
负责页面的解析与渲染;GUI线程和JS引擎线程是互斥的,当 JS 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。
- 事件触发线程
- 定时器触发线程
- http异步请求线程
渲染进程的创建
- 每次打开新标签页就会创建一个新的渲染进程。
- 但是,当在该标签页中打开新的标签页,而且两个标签页属于同一站点时,会继续用同一渲染进程。
浏览器的渲染过程
1、解析HTML生成DOM树。遇到img标签时加载图片。
此时display:none属性的节点存在DOM树中
2、解析css文件生成CSSOM树。
解析CSS文件(遇到背景图片链接,不加载),生成渲染规则树。
3、加载JavaScript脚本,执行js代码。
4、根据DOM树和CSSOM树生成渲染树。
结合DOM树和CSSOM树来构建渲染树,然后遍历DOM树,加载对应DOM的样式背景图片。渲染树中不包含display:none属性的节点)
5、遍历渲染树开始布局。
计算每个节点的位置和大小信息,输出包含位置和样式的布局树。此时第一次计算节点大小和位置,该过程为布局,之后每一次触发布局称为回流。
6、绘制。开始渲染页面
对布局树进行分层形成分层树,对每一层分别进行绘制,不同图层渲染互不影响。
可以创建新的图层的节点:
- 拥有层叠上下文属性的元素会单独为一层。
比如属性为非static的position、z-index、filter、opacity等
- 需要裁剪(clip)的地方也会创建图层
6、合成,将不同图层合并到一起,输出到屏幕,这个过程可以开启GUI加速。
因此图片的渲染不会阻塞DOM渲染。
CSS、JS、DOM解析和渲染阻塞问题
DOM解析
:DOM解析是指将HTML文件解析成为DOM树的过程。
DOM渲染
:是指将CSSOM树和DOM树结合生成render树,再将渲染树渲染到页面的过程。
- CSS的解析不会阻塞DOM解析,但会阻塞DOM的渲染。CSS的解析与DOM的解析并行。
- 同步的JS脚本执行会阻塞DOM的解析(由于JS引擎和渲染线程是互斥的)
CSS加载会阻塞后面JS的执行
补充知识
1、浏览器解析DOM时会预先加载具有引用标记的外部资源(例如有src
标记的<script>
标签),在解析到此标签时就直接运行,无需再加载资源,提高运行效率。
2、浏览器无法预先知道脚本的内容,因此在碰到<script>
标签时,会触发页面渲染,确保<script>
内能获取到DOM的新样式。
JS阻塞DOM问题怎么解决–JS的三种异步加载方式
defer和async属性只会改变脚本的执行时机,脚本的加载不受影响,也不会影响页面的解析
1、没有属性的script标签
页面解析遇到script标签时,会暂停解析,转而去加载和执行js脚本。会阻塞页面的解析。
2、defer属性的script标签
defer属性代表异步加载,延迟执行,会在HTML解析完成之后再执行脚本。会在DOMContentLoaded事件触发之前完成。
优先级高于DOMContentLoaded事件,脚本执行完成之后再触发DOMContentLoaded事件。
3、async属性的script标签
加载和执行都是异步,在脚本下载完之后立即执行。
页面没解析完时,会等脚本执行完再解析页面。
页面解析完成会直接执行脚本。
DOMContentLoaded和Load事件
对浏览器来说,页面加载主要有DOMContentLoaded和Load两个事件
- DOMContentLoaded:当页面解析完成后即DOM加载完成之后触发该事件.
defer优先级高于该事件,等脚本执行完再触发该事件
- load事件:等页面所有资源加载完才会触发,例如js、CSS、图片视频等。
渲染优化
1、从回流和重绘进行优化
- GPU加速
transform
opacity
will-change
- JS优化
对于scroll等事件进行防抖或节流处理
对于offset等敏感属性用变量缓存(每次获取offset时会触发一次布局即回流)
避免频繁的改动style,采用修改class的方式
2、其他渲染阶段优化
- 使用webworker多线程,将计算量大的运算放在worker线程处理,避免js阻塞页面渲染。
- 开启cdn加载css等静态资源,即加快css的加载速度。
- 避免动画实现中丢帧造成卡顿现象,尽量不用计时器实现动画,而采用
window.requestAnimationFrame(回调)