约 720 字大约 2 分钟

2022-04-14

提问

  1. 什么是文档预解析?
  2. CSS如何阻塞文档解析
  3. 渲染过程遇到 JS文件怎么处理?
  4. <script>asyncdefer 属性有什么作用?区别是什么?

文档预解析

当执行 Javascript 脚本时,另一个线程会解析剩下的文档,并加载后面需要通过网络加载的资源。 这种方式可以使资源并行加载从而使整体速度更快。

预解析并不改变DOM树,它将这个工作留给主解析过程,自己只解析外部资源的引用,比如外部脚本、样式表和图片。

Webkit和Firefox 都做了这个优化。

CSS如何阻塞文档解析

虽然样式表不改变DOM树,看起来没有必要停下文档的解析等待它们。 但是这里存在一个问题,Javascript 脚本执行时可能在文档的解析过程中请求样式信息, 如果样式还没有加载和解析,脚本将得到错误的值,显然会导致很多问题。

所以如果浏览器尚未完成 CSSOM 的下载和构建,但却在此时运行脚本,那么浏览器将延迟Javascript脚本执行和文档的解析, 直至其完成 CSSOM 的下载和构建。

在这种情况下,浏览器会先下载和构建 CSSOM,然后再执行,最后再继续文档的解析。

渲染过程遇到 JS文件

Javascript 的加载、解析和执行会阻塞文档的解析。 在构建 DOM时,HTML解析器若遇到了 Javascript,那么会暂时停止文档的解析,将控制权移交给 Javascript引擎, 等 Javascript引擎运行完毕,浏览器在从中断的地方恢复继续解析文档。

所以为了首屏渲染的速度更快,不应该在首屏就加载JS文档,这也是建议将 script 标签放在 body标签底部的原因。 但在现在,因为 script 标签有了 async 和 defer属性,也不一定需要放在body标签底部了。

<script>asyncdefer 属性

  • async 属性 表示 异步执行引入的 javascript 脚本。

    当前 javascript 加载时不会阻塞HTML文档的解析,加载完成后立即执行脚本。 即加载过程不阻塞HTML文档解析,但是加载完成开始执行仍然会阻塞HTML文档解析。 多个脚本的执行顺序无法保证。

  • defer 属性 表示 延迟执行引入的 javascript 脚本。

    当前 javascript 加载时不会阻塞HTML文档的解析,这两个过程是并行的。 当整个HTML解析完毕后在执行脚本文件。 并在 DOMContentLoaded事件触发之前完成执行脚本文件,多个脚本按顺序执行。