js阻塞dom的构建 && CSS通过js来阻塞DOM的构建
-
JavaScript脚本由于可能会修改DOM,因此会阻塞DOM的构建,这一点我们都知道;而CSS并不会操作或者改变DOM,因此通常我们认为CSS不会影响DOM的构建,只会影响后续的布局、绘制等过程,即会影响DOM的渲染。但其实CSS可以通过JavaScript来阻塞DOM的构建。
因为JavaScript是可以改变样式的,也就是具有修改CSS规则树的能力,而JavaScript脚本里是否有改变样式的操作,这一点在执行JavaScript之前是不可知的。因此,为保证JavaScript脚本的正确执行,在执行JavaScript之前,CSS规则树必须要先准备好(不然万一有修改CSS的操作呢)。
也就是说,若在构建DOM的中途存在阻塞DOM构建的JavaScript脚本,而此页面中还包含了外部 CSS 文件的引用,那么此时就需要等目前的CSS规则树(基于目前生成完的部分DOM树)构建完毕后,再开始JavaScript脚本的执行,等一切结束了,再继续DOM的构建。 -
UI线程与JS线程是互斥的,因为JS运行结果会影响到UI线程的结果,当JS线程运行的时候,UI线程处于冻结状态。(现在浏览器可能对某些事件做了特殊处理,比如监听了scroll事件,在滚动时还是能够流畅的播放动画)。
DOM与CSS
- 没有js的理想情况下,html与css会并行解析,分别生成DOM与CSSOM
- css的加载不会阻塞DOM的解析(能通过js阻塞)
- css的加载会阻塞DOM的渲染
DOM与JS
- JS的加载和执行会阻塞DOM的解析
- JS的加载和执行会阻塞DOM的渲染
异步加载JavaScript脚本
<script src="path/to/myModule.js" defer></script>
<script src="path/to/myModule.js" async></script>
<!-- defer是“页面DOM解析完再执行”,async是“js脚本下载完就执行” -->
- 相同点:
- 都只使用于外部脚本
- 都会立即异步下载js文件
- 都有兼容性的问题
- 不同点:
- defer在DOM解析完成之后在DOMContentLs:oaded之前执行脚本,且按照script标签出现的顺序执行(有些版本的浏览器不会顺序执行),因此,defer适合于与dom有关的脚本,也适用于执行有先后依赖的脚本
- async是在脚本下载完成之后立即执行,所以脚本执行的先后顺序不一定(谁先下载完谁先执行),也有可能会阻塞DOM的解析。因此,async适合第三方脚本,不操作dom
- tips:如果考虑兼容,最好是把script标签放在body的最后
浏览器加载ES6模块
- 使用type = ‘module’
- 属于异步加载,等同于打开了defer属性
<script type="module" src="./foo.js"></script>
补充DOMContentLoaded和load的调用时机:
1,解析HTML结构。
2,DOM树构建完成。//DOMContentLoaded
3,加载外部脚本和样式表文件。
4,解析并执行脚本代码。
5,加载图片等外部文件。
6,页面加载完毕。//load
在第2步,会触发DOMContentLoaded事件。在第6步,触发load事件。