defer与async属性
通常情况下 js 文件都是放在 body 结束标签前面的,因为如果放在 head 标签中,浏览器解析遇到 js 文件的话会阻塞解析 DOM 树的生成,直到下载完 js 文件。
因为浏览器解析网页时候是一行行解析的,如果 head 中存在 js 文件,解析到 js 时就会停下来等待 js 文件的加载。如果把 js 文件放在 body 结束标签前面,浏览器会优先加载 DOM,可以在下载 js 文件之前就看到 body 内容,浏览体验就会好些。
如果非要在 head 同步添加 js 文件加载,可以通过设置 defer 或 async 属性来避免上述问题。
# defer 属性
- 异步加载 script 标签中的 js 文件;
- 等到 html 页面解析完毕之后再去执行;
- 在 DOMCententLoad 事件之间触发;
- 如果有多个 defer 属性的标签,会按照先后顺序执行。
# async 属性
- 异步加载 js 文件
- js 文件加载完毕后就会执行
- 可能 DOMCententLoad 之前也可能在之后触发;
- 如果有多个 async 属性的标签,会按照加载完毕时间执行,而不是标签先后顺序
# ES6 中 script 标签 module
- 异步加载,不会造成浏览器阻塞
- 页面渲染完,再执行模块脚本
- 等同于 script 中的 defer 属性
# first paint 概念
浏览器的渲染是要等到 HTML 文件解析完(DOMContentLoad)之后才会构建和布局渲染树嘛?不完全是!现代浏览器为了更好地用户体验,渲染引擎会尝试尽快地在屏幕上显示内容,它不会等所有的 HTML 解析之后才开始构建和布局渲染树。在部分内容被解析时就会显示,就是说浏览器能够渲染不完整的 DOM 树和 CSSOM,尽量减少白屏时间。
而我们上述说的 defer、async 属性,它会降低 DOMCententLoad 事件触发的事件嘛,其实是不会的。defer 脚本在 DOMContentLoad 之前,DOM 解析之后执行,此属性只是尽可能浏览器更早解析 DOM,减少 first paint 时间。
编辑 (opens new window)
上次更新: 2022/09/03, 18:32:11