图解 script 标签中的 async 和 defer 属性
我们在工作中经常会碰到 script 标签,一般会有以下三种形式
<script src='xxx'></script>
<script src='xxx' async></script>
<script src='xxx' defer></script>
那么这三种形式的 script 标签有什么区别呢?且容我们一探究竟。
前置知识点
浏览器的渲染线程在解析 HTML 的过程中如果遇到 script 标签会暂停解析 HTML ,等带 Javascript 脚本下载并执行完成后才会继续解析 HTML 。因为解析 HTML 的过程其实就是在构建 DOM 树的过程,而 Javascript 脚本在执行的过程中是有可能修改 DOM 树结构的。

普通 script 标签
对于普通 script 标签而言,就是走的正常的解析 Javascript 的流程,先暂停 HTML 的解析,等待下载并执行 Javascript 之后再继续 HTML 解析。
以下是普通 script 标签执行时机的图解

如果某个 Javascript 脚本比较大或者网络不好,那么就可能在下载的时候耗费时间比较久,从而造成页面白屏; Javascript 执行时间过长,比如循环遍历了一个很大的数据,也是有可能造成白屏的。
async script
对于有 async 属性的 script 标签而言,遇到这种 script 标签并不会立即停止解析 HTML ,而是下载 JavaScript 和解析 HTML 同时进行,当 JavaScript 下载完成之后,再停止解析 HTML 转而执行刚下载好的 JavaScript ,待 JavaScript 执行完成再继续解析 HTML。
以下是async script 标签执行时机的图解

使用 async 属性的 script 标签不能保证执行顺序和我们在页面中写入的顺序是一致的,因为我们不能保证先出现的 script 标签就一定先下载完成,可能后面的 script 标签指向的文件更小,那么它就有可能先下载完成,从而先执行。所以,对于依赖执行顺序的 JavaScript 文件最好不要使用 async 属性。
defer script
对于有 defer 属性的 script 标签而言,遇到这种 script 标签不会停止解析 HTML , 而是同时解析 HTML 和 下载 JavaScript ,待 HTML 解析完成,再根据加入 script 的顺序执行 JavaScript。
以下是defer script 标签执行时机的图解
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ibc16z1s-1676850671058)(null)]](https://img-blog.csdnimg.cn/ca64f685cbcc4c7a8eadf68b8ff56fb8.png)
使用 defer 属性的 script 标签不会阻塞 HTML 的解析,且能保证 JavaScript 的执行顺序,但是这些 JavaScript 需要在 HTML 解析之后才会执行。
tips: IE9 以下不支持 defer 属性
总结
最后,根据上面的分析,不同类型 script 的执行顺序及其是否阻塞解析 HTML 总结如下:
| script 标签 | JS 执行顺序 | 是否阻塞解析 HTML |
|---|---|---|
<script> | 在 HTML 中的顺序 | 阻塞 |
<script async> | 网络请求返回顺序 | 可能阻塞,也可能不阻塞 |
<script defer> | 在 HTML 中的顺序 | 不阻塞 |



















