JS异步加载
了解浏览器在遇到async、defer属性的脚本执行顺序,我们可以利用这两个属性来改善JS的阻塞问题,使用这两个属性会有几种可能的情况:
- defer为true:延迟加载脚本,在文档完成解析完成开始执行,并且在DOMContentLoaded事件之前执行完成。
- async为true:异步加载脚本,下载完毕后再执行,在window的load事件之前执行完成
利用这两个属性异步加载js,还得了解它们的毛病:
- 使用defer属性,最好是外部的script
- 使用defer、async的脚本禁止使用document.write()方法
- 当脚本尝试访问的样式属性可能尚未加载的样式表时,浏览器会禁止该脚本等待样式表加载完成,这等于样式表阻塞了脚本的执行。所以使用defer、async的脚本最好不要请求样式信息时。
普通 script
先来看一个普通的 script 标签。
<script src="a.js"></script>
浏览器会做如下处理
- 停止解析 document.
- 请求 a.js
- 执行 a.js 中的脚本
- 继续解析 document
defer
<script src="d.js" defer></script><script src="e.js" defer></script>
- 不阻止解析 document, 并行下载 d.js, e.js
- 即使下载完 d.js, e.js 仍继续解析 document
- 按照页面中出现的顺序,在其他同步脚本执行后,
DOMContentLoaded
事件前 依次执行 d.js, e.js。
async
<script src="b.js" async></script><script src="c.js" async></script>
- 不阻止解析 document, 并行下载 b.js, c.js
- 当脚本下载完后立即执行。(两者执行顺序不确定,执行阶段不确定,可能在
DOMContentLoaded
事件前或者后 )
其他
- 如果 script 无 src 属性,则 defer, async 会被忽略
- 动态添加的 script 标签隐含 async 属性。
结论
- 两者都不会阻止 document 的解析
- defer 会在 DOMContentLoaded 前依次执行 (可以利用这两点哦!)
- async 则是下载完立即执行,不一定是在 DOMContentLoaded 前
- async 因为顺序无关,所以很适合像 Google Analytics 这样的无依赖脚本