HTML 文件解析过程常见问题

625 阅读3分钟

前言


作为一个前端开发人员,每天面对的无非就是 HTML、CSS 、JS这几类文件。在浏览器解析 HTML 文件需要下载 CSS、JS 或者图片。这时浏览器是通过何种方式下载和解析这些文件的呢?

JS 会阻塞 DOM 的解析吗?那会不会阻塞 DOM 渲染呢?


  1. script

    如果浏览器在解析过程中遇到一个不包含deferasync的script标签,浏览器会在此时停止 DOM 解析,通过发送 http 请求获取到当前 js 脚本,然后让 JS 引擎执行脚本内容,执行结束后返回结果并继续解析 DOM。大致过程如下,

    WechatIMG3.jpeg

  2. script async

    如果浏览器在解析的过程中遇到一个包含async的script标签,此时浏览器并不会阻塞 DOM 解析,异步请求对应的 JS 脚本下载完成之后,就在此刻中断 DOM 解析,让 JS 脚本执行完成之后,再继续执行 DOM 解析。图解情况如下,

    1630211550618.jpg

  3. script defer

    如果浏览器在解析的过程中遇到一个包含defer的script标签,此时浏览器并不会阻塞 DOM 解析,异步下载对应的 JS 脚本下载,等到 DOM 解析完成之后,再执行 JS 脚本。图解情况如下,

    1630211973652.jpg

结论:

  • 空标签的 script 和 含async属性的 script 标签会阻塞 DOM 的解析
  • defer属性的 script 标签并不阻塞 DOM 解析
  • 弄懂了解析过程,渲染也就明朗了。由于 JS 脚本内可能含有一个 DOM 操作,所以 JS 脚本是一定会阻塞 DOM 渲染的

这也就能解释 script 为什么一般都放在 html 文本底部。

CSS 会阻塞 DOM 的解析吗?那会不会阻塞 DOM 渲染呢?


正常情况下,CSS 是不会阻塞 DOM 的解析的。因为在解析生成 DOM 树和 CSSOM 树时是互不干扰的,但是 CSSOM 是会影响 DOM 的渲染的。若 CSS 加载阻塞或者解析过慢是会阻塞 DOM 渲染的。因为 DOM 渲染是通过渲染树进行渲染,而渲染树是结合DOM树和CSSOM树生成的。

在特殊的情况下,CSS也是可以阻塞 DOM解析的,具体分析请看下面这个HTML文本,

<html>
    <head>
        <style type="text/css" src = "index.css" />
    </head>
    <body>
        <p>CSS样式</p>
        <script>
            let e = document.getElementsByTagName('p')[0]
            e.style.color = 'blue'
        </script>
    </body>
</html>

当我在 JavaScript 中访问了p元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS也会阻塞DOM的解析。因为 JavaScript 阻塞了 DOM 解析,在当前情况下, CSS 又阻塞了 Javascript 脚本的运行。所以DOM解析暂时的别阻塞了。

这也就是为什么大多数的CSS文件是在html文本中的head标签中别引入,这样能在 DOM 解析过程中同时进行样式文件加载解析。同样在head通过style标签引入也是一样的。

img 会阻塞 DOM 的解析吗?那会不会阻塞 DOM 渲染呢?


首先需要了解一下图片加载和渲染时机:

  • 解析HTML【遇到img标签,同步加载图片】——> 构建DOM树
  • 加载样式 ——> 解析样式【遇到背景图片,不加载】——> 构建样式规则树
  • 加载JS脚本 ——> 执行脚本
  • 结合DOM树和样式规则树生成渲染树【加载对应样式规则树上的背景图片】
  • 计算元素位置并进行布局,即layout过程
  • 绘制painting【开始渲染图片】

由上可以看出不管是背景图片还是img加载的图片都不会对DOM解析进行阻塞,可以看出DOM解析并不会去关心图片资源。但是在painting过程中,需要用到图片资源,若是图片资源下载过慢是会出现阻塞DOM渲染的。还有注意区分懒加载与此的区别!