阻塞还是不阻塞,做个实验就好了

前言

浏览器在解析 HTML 时,遇到 CSS 和 JS 可能会阻塞住,这个结论网上有很多,可自行搜索。

对于 JS,有如下结论:

  1. JS 加载会阻塞 HTML 的解析和渲染
  2. JS 执行会阻塞 HTML 的解析和渲染

对于 CSS,有如下结论:

  1. CSS 加载不会阻塞 HTML 的解析,会阻塞 HTML 的渲染
  2. CSS 加载不会阻塞 JS 的加载,会阻塞 JS 的执行

下面,我们做几个实验来验证上述的结论。

实验验证

JS 加载会阻塞 HTML 的解析和渲染

这个只需验证会阻塞解析即可,因为渲染的前提是先解析。我们构造这样一个 HTML 文件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test for Parsing HTML</title>
  </head>
  <body>
    <div id="first">First Part</div>
    <script src="./big.js"></script>
    <div id="second">Second Part</div>
  </body>
</html>

其中 big.js 里面放一些注释就好了,体积大概 1 MB 左右。启动静态文件服务器,打开浏览器器并限速为 Fast 3G(这样 big.js 加载时间会大于 5s),访问上述文件,此时快速打开 console 面板,多次输入:

console.log(document.querySelector('#second'), performance.now())

以下是我的结果:

阻塞还是不阻塞,做个实验就好了

我们知道 HTML 的解析目的是为了生成 DOM。从上面的验证结果中发现,在 big.js 的加载过程中,第二个 div 的 DOM 确实一直没有构建出来,所以 “JS 加载会阻塞 HTML 的解析” 是成立的。

JS 执行会阻塞 HTML 的解析和渲染

同样的,我们也只需要验证会阻塞解析即可。聪明的你肯定想到把上面例子中的 JS 改成内联的就可以验证了,但是如果你这么做的话,发现当 JS 在运行时,根本没法在 console 面板中进行输入。我们换成下面的例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test for Parsing HTML</title>
  </head>
  <body>
    <div id="first">First Part</div>
    <script>
      const start = performance.now()
      while (performance.now() - start < 1000) {}
      console.log(document.querySelector('#second'))
    
</script>
    <div id="second">Second Part</div>
  </body>
</html>

输出结果是 null。当然,这个结果对于我们来说是显而易见的事情,那为啥这可以用来证明呢?现在假设 JS 的执行不阻塞 HTML 的解析,那么在执行 while 循环的时候后面的内容应该早就解析完成了(毕竟有 1 秒钟的时间),那么 console.log 就不应该输出 null。而现在输出了 null,说明假设不成立,“JS 的执行会阻塞 HTML 的解析”。

CSS 加载不会阻塞 HTML 的解析,会阻塞 HTML 的渲染

还是先上例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test for Parsing HTML</title>
    <link rel="stylesheet" href="./big.css" />
  </head>
  <body>
    <div id="div">I am a DIV.</div>
  </body>
</html>

其中 big.css 里面也是放 1mb 左右的注释即可。然后启动静态文件服务器,打开浏览器器并限速为 Fast 3G(这样 big.css 加载时间会大于 5s),访问上述文件,此时快速打开 console 面板,多次输入:

console.log(document.querySelector('#div'), performance.now())

可以看到输出结果都不是 null,从而可以验证“CSS 加载不会阻塞 HTML 的解析”。

还是这个例子,我们通过肉眼可以发现页面内容要等待比较长的时间才能显示出来,从而可以验证“CSS 加载会阻塞 HTML 的渲染”。

CSS 加载不会阻塞 JS 的加载,会阻塞 JS 的执行

第一部分很好证明,用下面这个例子即可:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test for Parsing HTML</title>
    <link rel="stylesheet" href="./big.css" />
    <script src="./big.js"></script>
  </head>
  <body>
    <div id="div">I am a DIV.</div>
  </body>
</html>

打开浏览器 Network 面板,可以看到两个资源是几乎是同时加载的:

阻塞还是不阻塞,做个实验就好了

从而证明“CSS 加载不会阻塞 JS 的加载”。

对于后面一部分,我们构造这样的例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Test for Parsing HTML</title>
    <link rel="stylesheet" href="./big.css" />
  </head>
  <body>
    <div id="first">First</div>
    <script>
      console.log(performance.now())
    
</script>
    <div id="second">Second</div>
  </body>
</html>

上面的例子中,最后输出的结果在我的机器上是 6000 多毫秒(限速为 Fast 3G),从而证明了“CSS 加载会阻塞 JS 的执行”。

同时,如果我们在浏览器中多次输入 console.log(document.querySelector('#first'), document.querySelector('#second')),会得到如下结果:

阻塞还是不阻塞,做个实验就好了

分析这个结果,我们发现在 big.css 加载的时候,第一个 div 已经被解析出来了,但是由于 JS 的执行被 CSS 的加载所阻塞,而 JS 的执行又会阻塞 HTML 的解析,所以第二个 div 还未被解析。直到 JS 被执行完后,第二个 div 才被解析出来。

通过这几个例子,是不是对浏览器解析 HTML 的过程又有了进一步的理解呢?


原文始发于微信公众号(前端游):阻塞还是不阻塞,做个实验就好了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/282162.html

(0)
前端游的头像前端游bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!