1. 浏览器渲染页面的原理
html文件:字节 -> 字符 -> token -> 节点对象 -> DOM
css文件:字节 -> 字符 -> token -> 节点对象 -> CSSOM
DOM+CSSOM=渲染树
根据渲染树进行布局
- 浏览器发送请求以后,服务器返回html文件,第一步开始解析html文件,并且构建dom
- 在解析html文件的时候遇到link标签,浏览器就去请求css文件,
- 请求css文件的过程同时也继续解析html文件
- 若解析html文件遇到script标签,浏览器就去请求js文件,服务器就会陆续返回css和js文件
- 遇到js文件时,html会暂停解析,等js执行完成后html再继续解析
- 如果先返回并解析完成js文件,也是会发生阻塞,不能先执行js文件,必须等CSSOM构建完成了才执行js文件
- 接下来就解析css文件,并且构建CSSOM树,此时浏览器依然可以去下载并且解析JS文件
- 等CSSOM构建完成以后,就去执行js里的内容了
- js执行完成后,构建DOM后,形成渲染树
- 然后进行布局
- 最后绘制
2. 在解析过程中遇到 JavaScript 脚本,如何规避阻塞
script 标签不阻塞页面的方法:
<script>标签没有src特性,那么async和defer特性会被忽略。
defer特性:- 具有
defer特性的脚本总是要等到 DOM 解析完毕,但在DOMContentLoaded事件之前执行。 - 具有
defer特性的多个js脚本并行下载(下载没有顺序),文档顺序执行 defer用于需要整个 DOM 的脚本,脚本的相对执行顺序很重要的时候。
- 具有
async特性:async异步脚本以“加载优先”的顺序执行。DOMContentLoaded可能在async之前或之后触发,不能保证谁先谁后。async用于独立脚本,例如计数器或广告,这些脚本的相对执行顺序无关紧要。
- 动态添加脚本:
- 默认情况下,动态脚本的行为是“异步”的
- 先加载完成的脚本先执行(“加载优先”顺序)
let script = document.createElement('script'); script.src = "/article/script-async-defer/long.js"; document.body.append(script); // (*)
参考: