script 标签中的 async 和 defer 的区别

在前端开发中,<script>标签的asyncdefer属性均用于优化脚本加载与页面渲染的关系,避免脚本阻塞页面解析,但二者在执行时机、加载顺序、适用场景上存在关键区别。下面从核心概念、工作流程、对比分析和实践建议四个维度详细说明:

一、核心概念:为什么需要 async/defer?

默认情况下(无async/defer),浏览器解析HTML时遇到<script>标签会:

  1. 暂停HTML解析(阻塞渲染);
  2. 下载脚本文件;
  3. 下载完成后立即执行脚本;
  4. 执行结束后才恢复HTML解析。

这种"阻塞"会导致页面加载缓慢(尤其是脚本体积大或网络差时)。

asyncdefer的核心作用是:让脚本下载与HTML解析并行进行,仅在特定时机执行脚本,减少对页面渲染的阻塞。

二、async 属性:"异步加载,加载完立即执行"

async(异步)的核心逻辑是"加载优先,执行不等待",适用于不依赖其他脚本/DOM、也不被其他脚本依赖的独立脚本(如统计脚本、广告脚本)。

工作流程

  1. 浏览器解析HTML时,遇到<script async src="xxx.js">,会并行下载脚本(不暂停HTML解析);
  2. 脚本下载完成后,会立即暂停HTML解析,执行该脚本;
  3. 脚本执行结束后,恢复HTML解析。

关键特性

  • 执行时机不确定:脚本的执行顺序完全取决于"下载速度",下载快的先执行(即使脚本在HTML中顺序靠后,也可能先执行);
  • 不保证顺序 :若多个async脚本存在依赖关系(如A脚本依赖B脚本),可能出现A先执行、B后执行的错误;
  • 执行时阻塞解析:脚本下载完成后会"插队"执行,此时仍会暂停HTML解析(但下载阶段不阻塞)。

示例

js 复制代码
<!-- 脚本1体积小,脚本2体积大 -->
<script async src="small.js"></script> 
<script async src="large.js"></script> 
<!-- 实际执行顺序:small.js可能比large.js先执行(因下载快),与HTML中顺序无关 -->

三、defer 属性:"异步加载,解析完再执行"

defer(延迟)的核心逻辑是"加载并行,执行排队",适用于依赖DOM结构、或依赖其他脚本的脚本(如初始化页面的脚本、依赖jQuery的插件)。

工作流程

  1. 浏览器解析HTML时,遇到<script defer src="xxx.js">,会并行下载脚本(不暂停HTML解析);
  2. 脚本下载完成后,不立即执行,而是等待HTML解析完全结束 (即触发DOMContentLoaded事件前);
  3. 所有defer脚本按HTML中的声明顺序依次执行。

关键特性

  • 执行时机固定:必须等到HTML解析完才执行,不会"插队"阻塞解析;
  • 保证顺序 :多个defer脚本的执行顺序与它们在HTML中的顺序完全一致(即使后声明的脚本先下载完,也会等待前一个执行);
  • 依赖安全 :若脚本A依赖脚本B,只需在HTML中让B排在A前面(均加defer),即可确保B先执行。

示例

js 复制代码
<!-- 脚本1依赖脚本2,脚本2体积大 -->
<script defer src="large.js"></script>  <!-- 声明在前 -->
<script defer src="small.js"></script>  <!-- 声明在后 -->
<!-- 实际执行顺序:large.js先执行,small.js后执行(与声明顺序一致),且都在HTML解析完后执行 -->

四、async vs defer 核心对比

为了更清晰区分,下表从6个关键维度对比二者差异:

对比维度 async defer
下载与解析关系 下载与HTML解析并行 下载与HTML解析并行
执行时机 下载完成后立即执行 HTML解析完全结束后执行
执行顺序 不保证(按下载速度排序) 保证(按HTML声明顺序排序)
是否阻塞解析 执行时阻塞,下载时不阻塞 下载和执行时均不阻塞
依赖支持 不支持(无法依赖其他脚本) 支持(可按顺序依赖其他脚本)
适用场景 独立脚本(统计、广告、监控) 依赖DOM/其他脚本(初始化、插件)

五、与默认脚本(无属性)的对比

脚本类型 下载阶段是否阻塞HTML解析 执行阶段是否阻塞HTML解析 执行顺序
默认脚本(无属性) 是(暂停解析,先下载) 是(执行时继续暂停) 按HTML顺序
async 脚本 否(并行下载) 是(执行时暂停) 按下载速度
defer 脚本 否(并行下载) 否(解析完再执行) 按HTML顺序

六、实践建议

  1. 优先用 defer 的场景
    • 脚本依赖DOM(如操作<div id="app">),需等HTML解析完才能执行;
    • 脚本间有依赖关系(如A依赖B,B依赖jQuery),需保证执行顺序;
    • 页面核心功能脚本(如初始化交互、渲染内容)。
  1. 优先用 async 的场景
    • 脚本完全独立(不依赖任何DOM/其他脚本,也不被其他脚本依赖);
    • 非核心脚本(如百度统计、Google Analytics、广告脚本),早执行或晚执行不影响页面功能。
  1. 注意事项
    • async/defer仅对外部脚本(带src属性)有效 ,对内嵌脚本(<script>...</script>)无效;
    • 若同时设置asyncdefer,浏览器会忽略defer,仅按async规则执行;
    • 即使使用defer,脚本也应避免在DOMContentLoaded事件后才执行关键逻辑(因defer已确保在该事件前执行)。
相关推荐
lkbhua莱克瓦241 小时前
项目知识——Next.js App Router体系
开发语言·javascript·项目知识
浪浪山_大橙子1 小时前
使用Electron+Vue3开发Qwen3 2B桌面应用:从想法到实现的完整指南
前端·人工智能
狗哥哥1 小时前
聊聊设计模式在 Vue 3 业务开发中的落地——从一次代码重构说起
前端·架构
爱吃大芒果2 小时前
从零开始学 Flutter:状态管理入门之 setState 与 Provider
开发语言·javascript·flutter
shenzhenNBA2 小时前
如何在python文件中使用日志功能?简单版本
java·前端·python·日志·log
掘金泥石流2 小时前
分享下我创业烧了 几十万的 AI Coding 经验
前端·javascript·后端
用户47949283569152 小时前
JavaScript 为什么选择原型链?从第一性原理聊聊这个设计
前端·javascript
new code Boy2 小时前
vscode左侧栏图标及目录恢复
前端·javascript
唐诗2 小时前
Git提交信息太乱?AI一键美化!一行命令拯救你的项目历史🚀
前端·ai编程