浏览器渲染原理 (二)html中的css、javascript、dom之间的解析和相互阻塞关系

将欲取之,必先与之,是谓微明。柔弱胜刚强。——老子

引子

我们在看一些前端优化规则的时候,比如雅虎军规等等,都有看到 style 写在 head 中,但是外链 script 写在 body 的最后,以优化性能,都知道应该怎么做,但是不知道其中的原理。
如果还不知道浏览器渲染的原理的,看一看浏览器渲染原理这一篇文章。其实这个就是考验大家对 html 中的 css、javascript、dom 之间的解析和相互阻塞关系。

JavaScript 会阻塞 CSS、DOM 吗

提出自己观点

当我们把 script 标签写到页面的顶部时,dom 树在解析的时候检测到 script 标签是,会加载 script 里面的内容并且执行。我们假设在执行javascript 会阻塞 dom的解析和渲染,阻塞 css的解析和加载。

验证自己的观点

在验证之前我们先把 chrome 的网速调到 40kb 每秒的下载和上传数据
第一步
html operation
第二步
html operation

我们来验证这个结论:
html 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
console.log('start load');
function h () {
console.log(document.querySelectorAll('h1'))
};
setTimeout(h, 0);
</script>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<style>
h1 {
color: red;
}
</style>
<script>
console.log('end load');
setTimeout(h, 0);
</script>
</head>
<body>
<h1>测试阻塞加载</h1>
</body>
</html>

加载到jquery 文件后,会先下载远程的 jquery 并且执行他,他会阻塞 dom 的解析和渲染css 解析和渲染,一直是白屏,等 jquery执行完成了才接着解析 Dom 和 cssom 并且渲染,console.log 打印 h1 标签也是空数组。
如下图所示:
html operation

总结

javascript 加载会阻塞 css 解析和渲染
javascript 加载会阻塞 dom 解析和渲染

css 加载会阻塞 JavaScript 的加载和执行、会阻塞 Dom 的解析和渲染?

提出自己观点

因为上面我们已经验证过 JavaScript 会阻塞 Dom 的解析和渲染,同时也会解析 cssom 的解析和渲染,所以我们假设 css 的加载会阻塞Dom 的解析渲染,会阻塞JavaScript 的加载执行

验证我们的假设

在上面的代码基础上修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script>
console.log('start load');
function h () {
console.log(document.querySelectorAll('h1'))
};
setTimeout(h, 0);
</script>
<link href="https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet">
<style>
h1 {
color: red;
}
</style>
<script>
console.log('end load');
</script>
</head>
<body>
<h1>测试阻塞加载</h1>
</body>
</html>

执行结果如下图所示
html operation

css 加载对 Dom 的阻塞

如果按我们假设的 css 加载会阻塞 Dom 的解析和渲染,那么执行的结果,应该是首先是白屏,然后 h1 标签的 nodeList 应该是为空数组的,但是在执行的时我们看到 h1 标签的 nodeList 是有值的,注(还有 setTimeout 的作用是为了在下一个 Task 最先执行,感觉并不会影响我们的实验的结果。)
这表示我们一开始的假设是有问题的,css 加载会阻塞 Dom 的渲染有阻塞,但是并不会阻塞 Dom 的解析

css 加载对 JavaScript 的阻塞

css 加载会对后续的 JavaScript 的执行会造成阻塞。

总结

css 加载对 Dom 的解析没有阻塞,但是对于 Dom 的渲染造成了阻塞。
css 加载对 JavaScript 的执行会造成阻塞

总结

如果还不了解整体的渲染流程可以看以前我前面的文章,浏览器渲染原理 (一)在网址中输入一个网站后面都做了什么

  • **_JavaScript 的加载会阻塞 Dom 的解析和渲染,并且也会阻塞 css 的解析和渲染。_**
  • **_Css 的加载会阻塞 Dom 的渲染,并不会阻塞 Dom 的解析,也会阻塞 JavaScript 的执行。_**

参考

css 加载会造成阻塞吗?