1.CSS不会堵塞DOM解析(DOM Tree的生成)
2.CSS会堵塞页面的渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
100px;
height: 100px;
background: lightgreen;
}
</style>
<link rel="stylesheet" href="/css/sleep3000-common.css">
</head>
<body>
<div></div>
</body>
</html>
#1.sleep3000-common.css 会延迟3ms返回,样式就是设置div块为浅蓝色
#2.最终结果是浏览器会转圈圈三秒,之后呈现出一个浅蓝色的div,所以结果是CSS会堵塞页面的渲染。
3.JS会堵塞DOM解析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/js/blok.js">
</head>
<body>
<div></div>
</body>
</html>
#1.block.js代码如下
const arr = [];
for (let i = 0; i < 10000000; i++) {
arr.push(i);
arr.splice(i % 3, i % 7, i % 5);
}
const div = document.querySelector('div');
#2.最终结果浏览器转圈圈一会,这过程中不会有任何东西出现,之后打印出null。说明JS堵塞了DOM解析。
#3.如果JS文件体积太大,同时你确定没必要阻塞DOM解析的话,不妨按需要加上defer或者async属性,此时脚本下载的过程中是不会阻塞DOM解析的。
4.浏览器遇到 <script>且没有defer
或async
属性的标签时,会触发页面渲染。如果<script>标签前面有CSS资源,会等到CSS资源加载完毕之后再执行<script>脚本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/css/sleep3000-common.css">
</head>
<body>
<div></div>
<script src="/js/logDiv.js">
<style>
div {
background: lightgrey;
}
</style>
<script src="/js/sleep5000-logDiv.js"></script>
<link rel="stylesheet" href="/css/common.css">
</body>
</html>
#答案是等待3秒浅蓝色打印div,等待5秒浅灰色打印div,最后浅蓝色。由此可见,每次碰到<script>标签时,浏览器都会渲染一次页面。这是基于同样的理由,浏览器不知道脚本的内容,因而碰到脚本时,只好先渲染页面,确保脚本能获取到最新的DOM元素信息,尽管脚本可能不需要这些信息。
5.优化方案:
<script>
最好放底部,<link>
最好放头部,如果头部同时有<script>
与<link>
的情况下,最好将<script>
放在<link>
上面
6.附:defer 与 async
如果我们不想<script>堵塞页面的解析,我们可以给<script>标签添加defer或者async属性。defer和async的区别主要如下:
1.执行时机不同:
defer的脚本将在DOM解析完成后、触发 DOMContentLoaded 事件前执行
async的脚本一旦加载完毕,就会执行(不论是在DOM解析阶段还是DOMContentLoaded之前之后,但是一定是在window.load之前执行)
2.执行顺序不同:
defer能保证多个脚本按照书写顺序执行
async不能保证多个脚本的执行顺序