DOM和CSSOM的构建会相互影响吗

CSS加载会阻塞JS的执行吗?


通常情况下DOM和CSSOM是并行构建的,但是当浏览器遇到一个script标签时,DOM构建将暂停,直至脚本完成执行。但由于JavaScript可以修改CSSOM,所以需要等CSSOM构建完毕后再执行JS。

为什么CSS加载会阻塞JS的执行

我们都知道JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。

因为JavaScript可以修改网页的内容,它可以更改DOM,如果不阻塞,那么这边在构建DOM,那边JavaScript在改DOM,如何保障最终得到的DOM是否正确?而且在JS中前一秒获取到的DOM和后一秒获取到的DOM不一样是什么鬼?它会产生一系列问题,所以JS是阻塞的,它会阻塞DOM的构建流程,所以在JS中无法获取JS后面的元素,因为DOM还没构建到那。

JavaScript对关键渲染路径的影响不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建。

原本DOM和CSSOM的构建是互不影响,井水不犯河水,但是一旦引入了JavaScript,CSSOM也开始阻塞DOM的构建,只有CSSOM构建完毕后,DOM再恢复DOM构建。

这是什么情况?

这是因为JavaScript不只是可以改DOM,它还可以更改样式,也就是它可以更改CSSOM。前面我们介绍,不完整的CSSOM是无法使用的,但JavaScript中想访问CSSOM并更改它,那么在执行JavaScript时,必须要能拿到完整的CSSOM。所以就导致了一个现象,如果浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。

也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。

这会导致严重的性能问题,我们假设构建DOM需要一秒,构建CSSOM需要一秒,那么正常情况下只需要一秒钟DOM和CSSOM就会同时构建完毕然后进入到下一个阶段。但是如果引入了JavaScript,那么JavaScript会阻塞DOM的构建并等待CSSOM的下载和构建,一秒钟之后,假设执行JavaScript需要0.00000001秒,那么从中断的地方恢复DOM的构建后,还需要一秒钟的时间才能完成DOM的构建,总共花费了2秒钟才进入到下一个阶段。如图6-1所示。
图6-1 JS阻塞构建DOM并等待CSSOM
图6-1 JS阻塞构建DOM并等待CSSOM

例如下面不加载JS的代码:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test</title>
    <link rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y6/l/1,cross/9Ia-Y9BtgQu.css">
</head>
<body>
    aa
</body>
</html>

上面这段代码的执行性能结果如图6-2所示。
图6-2 CSS不阻塞DOM
图6-2 CSS不阻塞DOM

DOMContentLoaded 事件在116ms左右触发。

在代码中添加JavaScript:

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test</title>
    <link rel="stylesheet" href="https://static.xx.fbcdn.net/rsrc.php/v3/y6/l/1,cross/9Ia-Y9BtgQu.css">
</head>
<body>
    aa
    <script>
        console.log(1)
    </script>
</body>
</html>

DOMContentLoaded 事件在1.21s触发,如图6-3所示。
图6-3 CSS阻塞DOM
图6-3 CSS阻塞DOM

异步加载 css 会阻塞页面的渲染吗

异步加载不会阻塞渲染

在默认情况下,浏览器在加载CSS时将终止页面的样式呈现(同步加载),也就是加载CSS会阻塞DOM树的渲染(但并不会阻塞DOM树的构建),可以简单理解为:当在加载CSS的同时,也在构建DOM树,只是没有应用上样式。

CSS会阻塞DOM解析构建吗?会阻塞DOM渲染吗

CSS 不会阻塞 DOM 解析构建,但是会阻塞 DOM 渲染

浏览器的解析渲染过程,解析DOM生成DOM Tree,解析CSS生成CSSOM Tree,两者结合生成render tree渲染树,最后浏览器根据渲染树渲染至页面。

由此可以看出DOM Tree的解析和CSSOM Tree的解析是互不影响的,两者是并行的。

因此CSS不会阻塞页面DOM的解析构建,但是由于render tree的生成是依赖DOM Tree和CSSOM Tree的,因此CSS必然会阻塞DOM的渲染。

JS 脚本阻塞 DOM 构建,JS 脚本会不会对 css dom 树影响

会有影响

JavaScript的加载、解析与执行会阻塞DOM的构建,也就是说,在构建DOM时,HTML解析器若遇到了JavaScript,那么它会暂停构建DOM,将控制权移交给JavaScript引擎,等JavaScript引擎运行完毕,浏览器再从中断的地方恢复DOM构建。

也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件,这也是都建议将 script 标签放在 body 标签底部的原因。当然在当下,并不是说 script 标签必须放在底部,因为你可以给 script 标签添加 defer 或者 async 属性。

JS文件不只是阻塞DOM的构建,它会导致CSSOM也阻塞DOM的构建。

原本DOM和CSSOM的构建是互不影响,井水不犯河水,但是一旦引入了JavaScript,CSSOM也开始阻塞DOM的构建,只有CSSOM构建完毕后,DOM再恢复DOM构建。