前端秘密武器:async 与 defer,你用对了吗?

前端秘密武器:async 与 defer,你用对了吗?

在前端开发的江湖里,HTML、CSS 和 JavaScript 就是我们手中的三把利刃。而在使用 HTML 引入 JavaScript 文件时,asyncdefer 这两个属性就像是隐藏在利刃中的神秘符文,掌握它们的奥秘,能让我们的代码在性能和加载顺序上如鱼得水。今天,咱们就来揭开这两个属性的神秘面纱,看看它们到底有啥区别,又该怎么根据需求来选择使用。

开篇:前端性能的痛点

在正式介绍 asyncdefer 之前,咱们先聊聊前端开发中一个让人头疼的问题------页面加载性能。想象一下,你打开一个网页,页面半天都加载不出来,你是不是会急得直跺脚?这其中很大一部分原因可能就是 JavaScript 文件的加载和执行方式出了问题。

在 HTML 中,当浏览器遇到 <script> 标签时,默认情况下会暂停 HTML 的解析,去下载并执行 JavaScript 文件,直到这个文件执行完毕,才会继续解析 HTML。这就好比你在盖房子,盖到一半突然停下来去买材料,等材料买回来用完了才接着盖,这速度能快吗?所以,为了解决这个问题,asyncdefer 这两个属性就应运而生了。

认识 <script> 标签

在 HTML 中,我们通常使用 <script> 标签来引入外部的 JavaScript 文件。基本的语法如下:

html 复制代码
<!-- 这是一个简单的引入外部 JavaScript 文件的 <script> 标签 -->
<script src="example.js"></script>

这里的 src 属性指定了要引入的 JavaScript 文件的路径。当浏览器遇到这个标签时,会按照默认的方式来处理,也就是暂停 HTML 解析,下载并执行 JavaScript 文件。

深入了解 async 属性

什么是 async 属性?

async<script> 标签的一个布尔属性,当你给 <script> 标签加上 async 属性后,浏览器会异步地下载 JavaScript 文件。也就是说,浏览器不会因为遇到这个 <script> 标签而暂停 HTML 的解析,而是会继续解析 HTML,同时在后台下载 JavaScript 文件。当文件下载完成后,会立即暂停 HTML 解析,执行这个 JavaScript 文件。

代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Async Example</title>
    <!-- 这里使用了 async 属性,浏览器会异步下载这个 JavaScript 文件 -->
    <script async src="async.js"></script>
</head>

<body>
    <h1>Welcome to the Async World!</h1>
    <p>This is a paragraph to demonstrate the async behavior.</p>
</body>

</html>

特点总结

  • 异步下载:不会阻塞 HTML 解析,浏览器会在后台下载 JavaScript 文件。
  • 立即执行:文件下载完成后,会立即暂停 HTML 解析,执行该文件。
  • 加载顺序不确定 :如果有多个带有 async 属性的 <script> 标签,它们的加载顺序是不确定的,取决于哪个文件先下载完成。

使用场景

async 属性适合那些不依赖于其他脚本文件,并且不需要按照特定顺序执行的脚本。比如一些第三方的广告脚本、分析脚本等,这些脚本通常只需要在页面加载过程中某个时刻执行即可,不需要和其他脚本有严格的执行顺序。

深入了解 defer 属性

什么是 defer 属性?

defer 同样是 <script> 标签的一个布尔属性。当你给 <script> 标签加上 defer 属性后,浏览器会异步地下载 JavaScript 文件,但是不会立即执行,而是会等到 HTML 解析完成后,再按照 <script> 标签在 HTML 中出现的顺序依次执行这些脚本。

代码示例

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Defer Example</title>
    <!-- 这里使用了 defer 属性,浏览器会异步下载这个 JavaScript 文件 -->
    <script defer src="defer.js"></script>
</head>

<body>
    <h1>Welcome to the Defer World!</h1>
    <p>This is a paragraph to demonstrate the defer behavior.</p>
</body>

</html>

特点总结

  • 异步下载 :和 async 一样,不会阻塞 HTML 解析,浏览器会在后台下载 JavaScript 文件。
  • 延迟执行:文件下载完成后,不会立即执行,而是等到 HTML 解析完成后再执行。
  • 顺序执行 :如果有多个带有 defer 属性的 <script> 标签,它们会按照在 HTML 中出现的顺序依次执行。

使用场景

defer 属性适合那些依赖于 HTML 结构,并且需要按照特定顺序执行的脚本。比如一些需要操作 DOM 元素的脚本,因为这些脚本需要在 HTML 解析完成后才能正确地找到并操作相应的 DOM 元素。

asyncdefer 的对比

加载和执行顺序对比

为了更直观地理解 asyncdefer 的区别,我们来看一个对比示例。

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Async vs Defer</title>
    <!-- 第一个带有 async 属性的脚本 -->
    <script async src="async1.js"></script>
    <!-- 第二个带有 async 属性的脚本 -->
    <script async src="async2.js"></script>
    <!-- 第一个带有 defer 属性的脚本 -->
    <script defer src="defer1.js"></script>
    <!-- 第二个带有 defer 属性的脚本 -->
    <script defer src="defer2.js"></script>
</head>

<body>
    <h1>Async vs Defer Comparison</h1>
    <p>This is a paragraph to demonstrate the difference between async and defer.</p>
</body>

</html>

在这个示例中,两个带有 async 属性的脚本会异步下载,下载完成后会立即执行,它们的执行顺序不确定,取决于哪个文件先下载完成。而两个带有 defer 属性的脚本会异步下载,下载完成后不会立即执行,而是等到 HTML 解析完成后,按照在 HTML 中出现的顺序依次执行,也就是先执行 defer1.js,再执行 defer2.js

性能影响对比

从性能角度来看,asyncdefer 都能提高页面的加载性能,因为它们都允许浏览器在后台异步下载 JavaScript 文件,不会阻塞 HTML 解析。但是,由于 async 脚本下载完成后会立即执行,可能会在 HTML 解析过程中打断解析,导致页面渲染出现卡顿。而 defer 脚本会等到 HTML 解析完成后再执行,不会影响页面的渲染,所以在某些情况下,defer 可能会有更好的性能表现。

根据需求选择 asyncdefer

不需要特定顺序且不依赖 DOM 的脚本

如果你有一些脚本不依赖于其他脚本,也不需要操作 DOM 元素,只需要在页面加载过程中某个时刻执行即可,那么可以使用 async 属性。比如:

html 复制代码
<!-- 引入第三方广告脚本,使用 async 属性 -->
<script async src="https://example.com/ads.js"></script>

需要特定顺序且依赖 DOM 的脚本

如果你有一些脚本依赖于其他脚本,或者需要操作 DOM 元素,那么应该使用 defer 属性。比如:

html 复制代码
<!-- 引入一个需要操作 DOM 的脚本,使用 defer 属性 -->
<script defer src="dom-manipulation.js"></script>

多个脚本的情况

如果有多个脚本,并且它们之间有依赖关系,需要按照特定顺序执行,那么应该使用 defer 属性。如果这些脚本之间没有依赖关系,并且不需要按照特定顺序执行,那么可以使用 async 属性。

实战案例分析

案例一:优化页面加载性能

假设你有一个电商网站,页面上需要引入一些第三方的分析脚本和一些自定义的 JavaScript 脚本。分析脚本不需要和其他脚本有严格的执行顺序,而自定义脚本需要操作 DOM 元素。那么可以这样优化:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>E-commerce Website</title>
    <!-- 引入第三方分析脚本,使用 async 属性 -->
    <script async src="https://example.com/analytics.js"></script>
    <!-- 引入自定义脚本,使用 defer 属性 -->
    <script defer src="custom.js"></script>
</head>

<body>
    <h1>Welcome to our E-commerce Store!</h1>
    <p>Explore our amazing products.</p>
</body>

</html>

案例二:解决脚本依赖问题

假设你有一个网站,需要引入 jQuery 库和一些依赖于 jQuery 的自定义脚本。由于自定义脚本依赖于 jQuery,所以需要确保 jQuery 先加载并执行。可以这样做:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Website with jQuery</title>
    <!-- 引入 jQuery 库,使用 defer 属性 -->
    <script defer src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <!-- 引入依赖于 jQuery 的自定义脚本,使用 defer 属性 -->
    <script defer src="custom-jquery.js"></script>
</head>

<body>
    <h1>Welcome to our Website!</h1>
    <p>Check out our cool features.</p>
</body>

</html>

那么 ,在实际项目开发中使用

依据脚本依赖关系进行选择

  • 无依赖的脚本 :当脚本不依赖于其他脚本,并且执行顺序不会影响页面功能时,可使用 async 属性。像第三方广告脚本、社交媒体分享按钮脚本等,它们独立运行,无需与其他脚本协同工作。
html 复制代码
<!-- 引入第三方广告脚本,使用 async 属性 -->
<script async src="https://example.com/ads.js"></script>
  • 有依赖的脚本 :若脚本依赖于其他脚本,或者需要在特定脚本之后执行,那么使用 defer 属性。比如 jQuery 库和依赖于它的自定义脚本,要保证 jQuery 先加载并执行。
html 复制代码
<!-- 引入 jQuery 库,使用 defer 属性 -->
<script defer src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 引入依赖于 jQuery 的自定义脚本,使用 defer 属性 -->
<script defer src="custom-jquery.js"></script>

根据脚本对 DOM 的操作需求来选择

  • 不操作 DOM 的脚本 :对于那些不涉及 DOM 操作的脚本,使用 async 属性可以让脚本在后台异步下载,下载完成后立即执行,不会影响页面的渲染。
html 复制代码
<!-- 引入不操作 DOM 的脚本,使用 async 属性 -->
<script async src="analytics.js"></script>
  • 操作 DOM 的脚本 :需要操作 DOM 元素的脚本,要确保在 HTML 解析完成后执行,此时应使用 defer 属性。
html 复制代码
<!-- 引入需要操作 DOM 的脚本,使用 defer 属性 -->
<script defer src="dom-manipulation.js"></script>

多个脚本的情况

  • 无顺序要求 :若多个脚本之间没有依赖关系,且不需要按照特定顺序执行,可都使用 async 属性,这样能并行下载,加快页面加载速度。
html 复制代码
<!-- 多个无依赖关系的脚本,使用 async 属性 -->
<script async src="script1.js"></script>
<script async src="script2.js"></script>
  • 有顺序要求 :当多个脚本有依赖关系,需要按照特定顺序执行时,都使用 defer 属性,它们会在 HTML 解析完成后按顺序依次执行。
html 复制代码
<!-- 多个有依赖关系的脚本,使用 defer 属性 -->
<script defer src="base.js"></script>
<script defer src="module1.js"></script>
<script defer src="module2.js"></script>

结合性能测试和优化

  • 在实际项目中,要通过性能测试工具(如 Google PageSpeed Insights、Lighthouse 等)来评估使用 asyncdefer 属性后的页面性能。根据测试结果,对脚本的加载方式进行调整和优化。
  • 对于首屏加载至关重要的脚本,可考虑将其内联到 HTML 文件中,避免额外的网络请求。而对于非首屏所需的脚本,使用 asyncdefer 属性进行异步加载。

考虑兼容性

虽然现代浏览器对 asyncdefer 属性的支持良好,但在一些旧版本的浏览器中可能存在兼容性问题。在开发时,要进行充分的兼容性测试,必要时提供降级方案。

综上所述,在实际项目开发中,要根据脚本的依赖关系、对 DOM 的操作需求、多个脚本的执行顺序、性能测试结果以及兼容性等多方面因素,综合考虑使用 asyncdefer 属性,以达到最佳的页面加载性能和用户体验。

总结

在前端开发中,合理使用 asyncdefer 属性可以显著提高页面的加载性能和用户体验。async 属性适合那些不依赖于其他脚本,并且不需要按照特定顺序执行的脚本;而 defer 属性适合那些依赖于 HTML 结构,并且需要按照特定顺序执行的脚本。通过深入理解这两个属性的区别,并根据具体需求选择合适的属性,你就能让你的前端代码更加高效、稳定。

希望这篇文章能帮助你掌握 asyncdefer 属性的使用,让你在前端开发的道路上越走越顺!如果你还有其他问题,欢迎在评论区留言讨论。

相关推荐
Go_going_11 分钟前
【解决 el-table 树形数据更新后视图不刷新的问题】
前端·javascript·vue.js
进取星辰21 分钟前
10、Context:跨维度传音术——React 19 状态共享
前端·react.js·前端框架
wfsm23 分钟前
react使用01
前端·javascript·react.js
Rey_family32 分钟前
HTML 表单学习笔记
笔记·学习·html
小小小小宇34 分钟前
Vue 3 的批量更新机制
前端
阳光普照世界和平38 分钟前
从单点突破到链式攻击:XSS 的渗透全路径解析
前端·web安全·xss
MrsBaek1 小时前
前端笔记-AJAX
前端·笔记·ajax
前端Hardy1 小时前
第4课:函数基础——JS的“魔法咒语”
前端·javascript
孟陬1 小时前
如何检测 Network 请求异常 - PerformanceObserver
前端
前端小棒槌1 小时前
vue .sync 和 v-model 区别
前端