异步加载 JS 脚本时,async 与 defer 有何区别
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 456
Author 回答者: shfshanyue
以下图片取自 whatwg 的规范,可以说是最权威的图文解释了,详细参考原文
在正常情况下,即 <script> 没有任何额外属性标记的情况下,有几点共识
- JS 的脚本分为加载、解析、执行几个步骤,简单对应到图中就是
fetch(加载) 和execution(解析并执行) - JS 的脚本加载(fetch)且执行(execution)会阻塞 DOM 的渲染,因此 JS 一般放到最后头
而 defer 与 async 的区别如下:
- 相同点: 异步加载 (fetch)
- 不同点:
- async 加载(fetch)完成后立即执行 (execution),因此可能会阻塞 DOM 解析;
- defer 加载(fetch)完成后延迟到 DOM 解析完成后才会执行(execution)**,但会在事件
DomContentLoaded之前
拓展
当以下 index.js 加载时,属性是 async 与 defer 时,输出有何不同?
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<script src="./defer.js" defer></script>
<script src="./async.js" async></script>
<script>
console.log("Start");
document.addEventListener("DOMContentLoaded", () => {
console.log("DCL");
});
</script>
</body>
</html>derfer.js
console.log("Defer Script");async.js
console.log("Async Script");答:defer 总是在 DCL 之前输出,但是 async 有可能之前也有可能之后
Author 回答者: zhujianxiong
start/Async Script/DCL
Author 回答者: ethanlamm
start/Async Script/DCL
应该是 start => defer script => DCL,async script是脱离DOM的,和加载自身文件的大小有关,文件比较小的,加载快,然后执行;文件大的加载慢,然后执行。与DOMContentLoaded事件关系不确定。但JS脚本都是在Load事件前加载并执行完毕的,Load事件是兜底事件