js加载与执行阻塞浏览器ui渲染
前言
我们都知道,javascript 脚本应该放置在 html 文档的底部,其实这只是个比较保险的做法,要想javascript 脚本不会阻塞浏览器 ui 的渲染,需要知道以下 javascript 脚本加载与执行对 ui 渲染的影响。
先上结论
下面结论针对外链脚本,在此之前应该明白两个概念,加载 和 执行,加载就是下载到本地,执行就是运行脚本。
- 若脚本标签不带 defer 或者 async 属性,则脚本属于同步加载,此时脚本加载会阻塞浏览器解析 html 文档。
- 若脚本标签带 defer 或者 async ,则脚本属于异步加载,此时脚本加载不会阻止浏览器解析 html 文档。
- 脚本执行都会阻塞浏览器 ui 渲染(dom树构建,css树构建,渲染树构建,重排,重绘)。
- 在浏览器中 javascipt 和 ui 渲染公用一个线程,但是下载的时候浏览器会有一个线程池维护一些 io操作(网络IO,磁盘IO),所以下载的时候通过设置可以不阻塞 ui 渲染。
在此说一下, defer 和 async 的相同点在于 都是异步加载脚本,区别在于 async 加载完会立即执行,而 defer 是在 dom 树解析(仅仅是dom结构,不管样式表,图片这些)之后执行。
测试
针对上面的结论,我们挨个测试。
1. 若脚本标签不带 defer 或者 async 属性,则脚本属于同步加载,此时脚本加载会阻塞浏览器解析 html 文档。
看下面代码 html:
<!-- demo.html -->
<!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 src="http://localhost/study/add.php" ></script>
<style>
.box {
width: 400px;
height: 400px;
background: yellow;
}
</style>
</head>
<body>
<div class="box">1ddd2223fff3f1</div>
</body>
</html>
add.php
<?php
sleep(2);
将php 放到网站根目录下,打开 demo.html 即可测试,在此我们看到 add.php 返回的脚本大小很小,但是我们通过 sleep 模拟加载慢的情况,也就是延长加载时间,我们打开浏览器可以看到,经过一段时间后 页面上才渲染出 box 元素。
2. 若脚本标签带 defer 或者 async ,则脚本属于异步加载,此时脚本加载不会阻止浏览器解析 html 文档
看下面代码:
<!-- demo.html -->
<!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 src="http://localhost/study/add.php" defer ></script>
<style>
.box {
width: 400px;
height: 400px;
background: yellow;
}
</style>
</head>
<body>
<div class="box">1ddd2223fff3f1</div>
</body>
</html>
add.php
<?php
sleep(2);
我们给 script 标签加上 defer 或者 async ,打开浏览器看看,可以看到,box 元素瞬间显示在页面上。
3. 脚本执行都会阻塞浏览器 ui 渲染(dom树构建,css树构建,渲染树构建,重排,重绘)。
看下面代码:html:
<!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 src="demo1.js"></script>
<style>
.box {
width: 400px;
height: 400px;
background: yellow;
}
</style>
</head>
<body>
<div class="box">1ddd2223fff3f1</div>
</body>
</html>
demo1.js
let count = 0;
for (let i = 0; i < 1000000000; i ++) {
count ++;
}
打开浏览器我们发现,浏览器会过一段时间才会显示 box 元素,在这里我们通过大量计算,占用了线程,因为浏览器中 ui渲染和 javascript 公用一个线程,所以会阻塞。
最后
献上一张图(盗的)-.-


本文探讨了JavaScript脚本加载与执行对浏览器UI渲染的影响。不带defer或async属性的脚本会同步加载,阻塞HTML解析;而带有defer或async的脚本异步加载,不阻碍HTML解析。无论哪种方式,脚本执行都会阻塞浏览器UI渲染,包括DOM树构建、CSS树构建等过程。测试验证了这些结论。
1192

被折叠的 条评论
为什么被折叠?



