script 标签的同步加载和异步加载
使用 script
标签引入外部脚本默认是同步加载的,它会阻塞 HTML 的解析。可显式声明 async
和 defer
属性进行异步加载。
例如:
<script src="https://example.org/js/jqeruy.min.js" async>
<script src="https://example.org/js/jqeruy.min.js" defer>
async
属性和 defer
属性的区别:
-
async
:异步加载脚本,如果脚本下载完毕而 HTML 还未解析完成,会先停止解析而去执行脚本,执行完毕后再继续解析文档,多个 async 脚本无法保证执行的先后顺序。 -
defer
:异步下载脚本并且等待文档解析完毕后才会执行,按照 HTML 的规范,多个 defer 脚本会按照出现的先后顺序执行。
不同属性的总结
script 标签 | 执行顺序 | 是否阻塞解析 HTML |
---|---|---|
<script> | 在 HTML 中的顺序 | 阻塞 |
<script async> | 网络请求返回顺序 | 可能阻塞,也可能不阻塞 |
<script defer> | 在 HTML 中的顺序 | 不阻塞 |
除了直接在 HTML 文件中写入 script 标签,在项目中还常常动态插入 script 标签。
那动态添加的 script
元素是异步还是同步加载的?
默认情况下,动态添加的 script
元素是以异步方法加载的,相当于添加了 async
属性。
例如:
let script = document.createElement("script");
script.src = "gibberish.js";
document.head.appendChild(script);
同时,也可以明确的设定为同步加载
例如:
let script = document.createElement("script");
script.src = "gibberish.js";
script.async = false; // 显式声明为同步加载
document.head.appendChild(script);
参考资源:
- HTML Standard (whatwg.org)
- 图解 script 标签中的 async 和 defer 属性 - 掘金 (juejin.cn)
- Script标签加载与执行时机小结 (qq.com)
- JavaScript 高级程序设计 第 4 版 P39