浏览器渲染过程
浏览器渲染过程
- DOM 树:解析 HTML 构建 DOM(DOM 树)
- CSS 树:解析 CSS 构建 CSSOM(CSS 树)
- 渲染树:CSSOM 和 DOM 一起生成 Render Tree(渲染树)
- 布局(layout):根据Render Tree浏览器就知道网页中有哪些节点,以及各个节点与 CSS 的关系,从而知道每个节点的位置和几何属性
(重排)
- 绘制(Paint):根据计算好的信息绘制整个页面
(重绘)
过程如下图:
过程1、2、3非常快,但是4和5比较耗时
“重排” 和 “回流”是一个意思,指的是重新执行步骤4
“重绘” 指重新执行步骤5
.
DOM 树 和 渲染树 的区别:
DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素(display:none
)
渲染树不包括 head 和隐藏元素(display:none
),大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性
浏览器阻塞
自上而下解析HTML,逐渐构建起DOM tree,遇到style、link标签,会下载解析样式表,同时构建CSSOM tree,不会阻塞html的解析。但是遇到script标签,它会立即下载并执行得到的脚本,会阻塞HTML的解析。直到脚本里的同步代码部分(settimeout等异步操作之外的代码)执行完之后,再接着解析接下来的HTML。
直到将整个HTML文档的最后一个标签解析完毕,DOM tree生成完毕。然后CSSOM tree 、render tree生成,开始渲染。
1. js加载会阻塞DOM树的解析和渲染
如果把js放在页面顶部,下载和解析js的时间里面,dom迟迟得不到解析和渲染,浏览器一直处于白屏,所以把JavaScript文件放在页面底部更有利于页面快速呈现。
2. css加载不会阻塞DOM树的解析但会阻塞DOM树的渲染
如果把css文件引用放在HTML文档的底部,浏览器为了防止无样式内容闪烁,会在css文件下载并解析完毕之前什么都不显示,这也就会造成白屏现象。(但是在firefox浏览器中测试,会出现样式闪烁,这也算是不同浏览器的权衡吧,要么等css全解析完一起显示,要么先显示然后css解析完再重新画上新样式)
当css文件放在<head>
中时,虽然css解析也会阻塞后续dom的渲染,但是在解析css的同时也在解析dom,所以等到css解析完毕就会逐步的渲染页面了。
3. css加载会阻塞后面js语句的执行
因此,为了避免让用户看到长时间的白屏时间,我们应该尽可能的提高css加载速度,比如可以使用以下几种方法:
- 使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间)
- 对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩)
- 合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
- 减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)
defer和async
js加载会阻塞DOM树的解析和渲染,但<script>
标签的async和defer属性可以改变阻塞HTML解析的情况(但是较低版浏览器不支持,所以最佳的实践是,将<script>
放在</body>
前)。
async和defer
对于内联JavaScript是无效的
defer
设置了defer的script外链文件,在下载js文件期间不会阻塞HTML的解析,而且等js下载完毕时若HTML还没解析完毕,js会等到HTML文档解析完毕后再执行。如果有多个js下载文件,那么执行时也是按照顺序执行。
async
设置了async的script外链文件,在下载js文件期间不会阻塞HTML的解析,但是js下载完毕之后就会立即执行,无论现在HTML是否正在解析。
x