- dom解析:将页面上的标签、属性、文本档转换成dom对象,构建dom树
- css解析:将css代码解析,构建css树
- dom tree加css tree=render tree(渲染树) -->渲染页面
浏览器渲染流程:
- 浏览器开始解析目标HTML文件,执行流的顺序为自上而下。
- HTML解析器将HTML结构转换为基础的DOM(文档对象模型),构建DOM树完成后,触发DomContendLoaded事件。
- CSS解析器将CSS解析为CSSOM(层叠样式表对象模型),一棵仅含有样式信息的树。
- CSSOM和DOM开始合并构成渲染树,每个节点开始包含具体的样式信息。
- 计算渲染树中个各个节点的位置信息,即布局阶段。
- 将布局后的渲染树显示到界面上。
根据以上的流程,可以知道,当cssdom还没构建完成时,页面是不会渲染到浏览器界面的,这也是为什么当css下载过慢时,会出现白屏的现象。
link css不会堵塞DOM解析
//在头部插入<script defer src="/js/logDiv.js"></script>
const div = document.querySelector('div');
console.log(div);
但是会堵塞页面渲染;
<header>
<link rel="stylesheet" href="/css/sleep3000-common.css">
<script src="/js/logDiv.js"></script>
</header>
script会堵塞DOM解析;
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');
console.log(div);
浏览器遇到 script 标签时,会触发页面渲染
<body>
<div></div>
<script src="/js/sleep3000-logDiv.js"></script>
<style>
div {
background: lightgrey;
}
</style>
<script src="/js/sleep5000-logDiv.js"></script>
<link rel="stylesheet" href="/css/common.css">
</body>
如果想script不堵塞dom解析,我们可以给script标签加defer/async属性;当浏览器遇到script标签,且script没有defer和async属性的时候,会触发页面渲染。如果script标签前面有css资源,会等到css资源加载完毕再执行script脚本
优化方案:
script最好放底部,link最好放头部,如果头部同时,script和link的情况下,最好将script放在link上面
Defer和async的区别:
- 执行时机不同:
defer的脚本在dom解析完后,触发DOMContentLoad事件前执行
async脚本一旦加载完毕,就会执行(不论是在dom解析阶段还是DOMContentLoad之前之后,但是一定是在window.load之前执行) - 执行顺序不同:
defer能保证多个脚本按照书写顺序执行
async不能保证多个脚本的执行顺序