# script标签中defer和async

<figure><img src="/files/jGxCiTtNh66UdAyBotXT" alt=""><figcaption><p>async VS defer</p></figcaption></figure>

### 概述

async：异步下载，下载完立即执行（完全独立的脚本，DOM 和其他脚本不会等待它们，它们也不会等待其它的东西）。和脚步默认行为一致，即`<script>`标签上有没有async属性都一样，如上图所示。

defer：异步下载，等页面解析完后再执行

### 两者区别

* 对页面解析的影响：async由于下载完成就执行**会**阻塞页面解析；defer**不会**阻塞页面解析
* 执行顺序：多个带async属性的脚本的**执行顺序随机**，取决于各自下载完成的事件；多个带defer属性的脚本则严格按照各自出现在文档的先后**顺序执行**
* `DOMContentLoaded` ：async和`DOMContentLoaded` 事件不会彼此等待，不能保证谁先谁后；defer在 `DOMContentLoaded` 事件之前执行

> **可视化demo验证：**[**传送门**](https://yuyongyu08.github.io/async-vs-defer/)

### 与动态脚本关系

```javascript
let script = document.createElement('script');
script.src = "/article/script-async-defer/long.js";
document.body.append(script);
```

默认情况下，动态脚本的行为是**异步**的，相当于async。如果像达到defer的效果，可以显式地设置 `script.async=false`。

### 应用场景

* async：不依赖当前页面的第三方脚本，比如数据统计、广告等
* defer：严格控制脚本的执行顺序，比如先加载基础库文件再加载业务文件

### 延伸：页面生命周期

* DOMContentLoaded：DOM准备完毕时触发
* window\.onload：页面所有资源加载完成时触发
* window\.onbeforeunload：用户想要离开时触发，常用于用户未保存提示
* window\.onunload：用户最终离开时触发

`document.readyState` 是文档的当前状态，可以使用`readystatechange`事件监听状态变化：

```javascript
document.addEventListener("readystatechange", () => {
    switch (true) {
      case document.readyState === "loading":
        console.log("文档加载中");
        break;
      case document.readyState === "interactive":
        console.log("文档已被解析完成，与 DOMContentLoaded 几乎同时发生，但是在 DOMContentLoaded 之前发生");
        break;
      case document.readyState === "complete":
        console.log("文档加载中，文档和资源均已加载完成，与 window.onload 几乎同时发生，但是在 window.onload 之前发生");
        break;
      default:
        break;
    }
  });
```

tips：[XMLHttpRequest](/mian-shi-shu-li/qian-duan-ji-chu/web-api/xmlhttprequest.md)中也有个`onreadystatechange`事件。

参考：

* <https://zh.javascript.info/script-async-defer>
* <https://zh.javascript.info/onload-ondomcontentloaded>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.yuyy.tech/mian-shi-shu-li/qian-duan-ji-chu/html/script-biao-qian-zhong-defer-he-async.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
