JavaScript高级浏览器原理:渲染引擎解析页面步骤回流和重绘composite合成defer与async
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript高级浏览器原理:渲染引擎解析页面步骤回流和重绘composite合成defer与async相关的知识,希望对你有一定的参考价值。
文章目录
渲染引擎解析页面的步骤
我们常说的浏览器内核指的是浏览器的排版引擎,也称为浏览器引擎、页面渲染引擎,或样板引擎。一个网页下载下来后,就是由渲染引擎来帮助我们解析的。
解析过程如下:
解析1:html解析过程
默认情况下服务器会给浏览器返回index.html文件,所以解析HTML是所有步骤的开始。
解析HTML会构建DOM Tree:
解析2:生成CSS规则
- 在解析的过程中,如果遇到CSS的link元素,那么会由浏览器负责下载对应的CSS文件
- 注意:下载CSS文件是不会影响DOM的解析的
- 浏览器下载完CSS文件后,就会对CSS文件进行解析,解析出对应的规则树
- 我们可以称之为 CSSOM(CSS Object Model,CSS对象模型)
解析3:构建Render Tree(渲染树)
有了DOM Tree和CSSOM Tree后,就可以两个结合来构建Render Tree了。
注意:
- link元素不会阻塞DOM Tree的构建过程,但是会阻塞Render Tree的构建过程:可以理解为link元素对应css的下载,DOM Tree的构建不需要css,但Render Tree需要
- Render Tree和DOM Tree并不是一一对应的关系:如display为none的元素,不需要被渲染
解析4:布局layout和绘制Paint
布局layout:
- 渲染树会表示要显示的节点及其样式,但不表示节点的尺寸、位置等信息,这些信息由布局呈现
绘制Paint:
- 浏览器将布局阶段计算的每个frame转为屏幕上实际的像素点;
回流和重绘
回流
- 第一次确定节点的大小和位置,称之为布局
- 之后对节点的大小、位置修改重新计算称之为回流(即布局之后再次计算布局)
如何引起回流:
- DOM结构发生改变:添加或者移除节点
- 改变了布局
- 窗口resize
- 调用getComputedStyle方法获取尺寸、位置信息(有的浏览器在这里不会回流)
举个例子,有个box盒子很小,点了按钮后会变大,这样整个布局就会变化——这就是回流。
重绘
- 第一次渲染内容称之为绘制
- 之后重新渲染称之为重绘
如何引起重绘:修改背景色、文字颜色、边框颜色、样式等。
注意
- 回流一定会引起重绘,所以回流是一件很消耗性能的事情
- 开发中要尽量避免发生回流,方法如下:
- 修改样式时尽量一次性修改:如通过cssText修改,通过添加class修改
- 避免频繁的操作DOM:可以在一个DocumentFragment或者父元素中将要操作的DOM操作完成,再一次性的操作
- 避免通过getComputedStyle获取尺寸、位置等信息
- 某些元素使用position的absolute或者fixed:会引起回流,而是开销较小,不会对其他元素造成影响(因为脱标了)
特殊解析:composite合成
绘制的过程,可以将布局后的元素绘制到多个图层中。这是浏览器的一种优化手段。
默认情况下,标准流中的内容都是被绘制在同一个图层(Layer)中的;
而一些特殊的属性,会创建一个新的合成层(CompositingLayer),并且新的图层可以利用GPU来加速绘制。因为每个合成层的都是单独渲染的。
可以形成新的合成层的常见属性(了解):
- 3D transform
- video、canvas、iframe
- opacity 动画转换时
- position:fixed
- will-change:一个实验性的属性,提前告诉浏览器元素可能发生哪些变化
- animation或者transition 设置了opacity、transform
分层确实可以提高性能,但是它以内存管理为代价,因此不应作为web优化性能优势策略的一部分过度使用。
script元素和页面解析的关系
- 浏览器在解析HTML时,遇到script元素是不能继续构建DOM树的;
- 它会停止继续构建,先下载javascript代码,并执行JavaScript的脚本,等到JavaScript脚本执行结束后,才会继续解析HTML,构建DOM树;
原因:
- JavaScript的作用之一是操作并修改DOM,若等到DOM树构建完成并且渲染再执行JavaScript,会造成严重的回流和重绘,影响页面的性能
这会带来新的问题:
- 如今开发模式中(比如Vue、React),脚本往往比HTML页面更“重”,处理时间需要更长
- 会造成页面的解析阻塞,在脚本下载、执行完成之前,用户在界面上什么都看不到;
因此,我们为了解决这个问题,script元素给我们提供了两个属性(attribute):defer和async。
defer
作用:告诉浏览器不要等待脚本下载,而继续解析HTML,构建DOM Tree。
- 脚本由浏览器下载,不会阻塞DOM Tree的构建过程
- 如果脚本提前下载了,它会等待DOM Tree构建完成,在DOMContentLoaded事件之前先执行defer中的代码
- 即:DOM Tree构建完成——执行defer中的代码——发生DOMContentLoaded事件
- 多个带defer的脚本保持正确的顺序执行的(先执行第一个defer,执行第二个defer)
- 从某种角度来说,defer可以提高页面的性能,推荐放到head元素中(提前让浏览器去下载)
- defer 仅适用于外部脚本 ,对于script默认内容会被忽略
即,不要这样加:
<!--加在这里没用的-->
<srcipt defer>
....
</srcipt>
async
async是让一个脚本完全独立的:
- 浏览器不会因 async 脚本而阻塞(与 defer 类似)
- async脚本不能保证顺序,它是独立下载、独立运行,不会等待其他脚本
- async不能保证在DOMContentLoaded之前或者之后执行
defer与async
- defer通常用于需要在文档解析后操作DOM的JavaScript代码,并且对多个script文件有顺序要求的
- async通常用于独立的脚本,对其他脚本,甚至DOM没有依赖的
参考
coderwhy的课
浏览器页面渲染过程
浏览器渲染原理
JavaScript高级 | 浏览器渲染过程
以上是关于JavaScript高级浏览器原理:渲染引擎解析页面步骤回流和重绘composite合成defer与async的主要内容,如果未能解决你的问题,请参考以下文章