【HTML】defer 和 async 属性在 script 标签中分别有什么作用?

需要这两个属性的原因?

首先我们要知道的是,浏览器在解析 HTML 的过程中,遇到了 script 元素是不能继续构建 DOM 树的。

  • 它会停止解析构建,首先去下载 js 代码,并且执行 js 的脚本;
  • 只有在等到 js 脚本执行结束之后,才会继续解析 html,构建 DOM 树。

那为什么要这样做呢?

  • 因为 js 的作用之一就是操作 DOM,并且可以修改 DOM;
  • 如果等到 DOM 树构建完成并且渲染后再去执行 js,就会造成严重的回流重绘,影响页面性能;
  • 所以,在遇到 script 标签的时候,浏览器采取了先加载执行后构建 DOM 树的方案。

虽然是解决了回流和重绘的问题,但这又产生了新的问题!(解决一个问题产生了新的问题😂)

在现在的网页开发模式中(Vue、React),往往 js 脚本比 HTML 结构更“重”,需要加载和处理的时间更长。

这样就会导致页面的解析阻塞(在脚本完成下载、执行之前,用户在界面上什么都看不到)。

为了解决上面的问题,script 元素给我们提供了两个属性来处理:deferasync

defer 的作用

defer 翻译过来就是延迟的意思

defer 属性告诉浏览器不要等待脚本下载,而是继续解析 HTML、构建 DOM Tree。

  • 脚本会又浏览器来进行下载,但是不会阻塞 DOMTree 的构建过程;
  • 如果脚本提前下载好了,它会等待 DOM Tree 构建完成,在 DOMContentLoaded 事件之前执行 defer 中的代码。

下面举个例子:

我们创建了一个 defer.js 文件并在脚本执行的时候添加了 defer 属性,最后我们可以看到 DOMContentLoaded 会等待 defer 中的代码先执行完成。

在这里插入图片描述
在这里插入图片描述
另外我们要注意的是,多个 defer 的脚本是可以保持顺序执行的。

在这里插入图片描述
在这里插入图片描述
从某种角度来说,defer 是可以提高页面性能的,并且推荐把带有 defer 属性的 script 标签放到 heade 元素中。

async 的作用

async 翻译过来是异步的意思

async 的特性和 defer 有些类似

  • 浏览器不会因为 async 脚本的下载而阻塞(和 defer 类似)
  • 但是在带有 async 属性的脚本会在下载完成后立即执行,并且不能保证在 DOMContentLoaded 之前或者之后执行,我们要知道在脚本执行的时候是会阻塞 DOMTree 的构建。
  • 还有就是 async 脚本是不能保证顺序的,它是独立下载、独立运行,不会等待其他脚本;

在这里插入图片描述
在这里插入图片描述

具体的执⾏时机图解

绿色-HTML 解析;黑色-停止 HTML 解析;黄色-脚本下载;棕色-脚本执行;
在这里插入图片描述

总结

script 标签的 defer 和 async 属性都是用来控制外部脚本的加载和执行方式的,他们对于改善页面加载非常有帮助。

但是他们的机制并不相同:

  • defer 下载不会阻止 DOM 的构建,但是在 DOMTree 构建完成后,在 DOMContentLoaded 事件之前执行,并且 defer 脚本的执行是有序的。
  • async 下载同样不会阻止 DOM 的构建,但是不会保证在 DOMcontentLoaded 之前或者之后执行,也不能保证顺序,它的每个脚本都是独立的。

所以他们的应用场景是这样的:

  • defer 通常用于需要在文档解析后操作 DOM 的 js 代码,并且对多个脚本文件有顺序要求
  • async 通常用于独立的脚本,对其他脚本,甚至对 DOM 没有依赖的脚本。

在现代化的框架开发中,已经不需要我们手动设置 async 和 defer 了,在使用脚手架的时候,一遍会根据我们需要自动加上 defer 属性,某些特殊场景下,比如第三方分析工具或者是广告追踪脚本等,需要我们自己加上 async 属性。

### HTML `script` 标签中 `defer` 与 `async` 属性的区别及用法 #### 基本定义 在 JavaScript 中,`<script>` 标签用于引入外部 JavaScript 文件或包含嵌入式 JavaScript 代码。为了优化页面加载性能并控制脚本的执行时机,HTML 提供了两种特殊的属性——`defer` `async`。 #### `defer` 属性 当 `<script>` 标签带有 `defer` 属性时,浏览器会继续解析渲染后续的文档内容,而不会阻塞 DOM 构建过程[^3]。脚本会在整个 HTML 文档解析完成后立即按顺序执行,这意味着如果页面中有多个带有 `defer` 属性的脚本,则它们会按照其在 HTML 中出现的顺序依次执行[^5]。 以下是使用 `defer` 的示例代码: ```html <script src="script1.js" defer></script> <script src="script2.js" defer></script> ``` #### `async` 属性 对于具有 `async` 属性的 `<script>` 标签,浏览器同样不会因为下载该脚本文件而停止解析其他部分的内容[^4]。然而,一旦脚本被成功获取回来之后就会立刻被执行,而不等待任何其他的资源或者操作完成。需要注意的是,这种行为可能导致不同脚本之间的执行次序变得不可预测,具体取决于各个请求返回的速度差异。 下面是一个简单的例子展示了如何应用 `async` 属性: ```html <script src="library.js" async></script> <script src="app.js"></script> <!-- 这里可能还未等到 library.js 加载完毕 --> ``` #### 主要对比 | 特性 | `normal (no attribute)` | `defer` | `async` | |-----------------|-------------------------------|----------------------------------|---------------------------------| | **下载阶段** | 阻挡DOM构建 | 并行下载 | 并行下载 | | **执行阶段** | 按照遇到的位置暂停解析直到运行完当前脚本 | 在DOMContentLoaded事件触发前依序执行 | 尽早尽可能快地单独执行 | 总结来说,在实际开发过程中可以根据需求选择合适的策略来提升网页的整体表现力。例如,如果你希望某些非关键性的第三方统计工具尽快发挥作用但又不影响主要业务逻辑的话,那么就可以采用 `async` 方式;而对于那些需要确保特定先后关系才能正常运作的部分则更适合运用 `defer` 技术[^1]。 ### 结论 通过上述分析可以看出,虽然两者都能实现异步加载效果从而改善首屏呈现速度等方面的优势,但是由于各自独特的特性决定了适用场景也有所不同。因此理解清楚两者的本质区别是非常重要的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值