前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库script defer async 执行顺序 解析
HTML语义与文档

script 的 defer 和 async 什么时候执行?

外部经典脚本加 defer 后,下载可与 HTML 解析并行,解析完成后按标签顺序执行,再触发 DOMContentLoaded。加 async 后也是并行下载,但谁先下载好谁先执行,会打断当时的解析,不保证脚本之间的顺序。

前端进阶之旅 · 一题精讲更新于 2026.09.29
HTML#语义与文档#异步编程
先看核心答案读代码示例
理解线索

下载与执行是两个时间点

  1. 默认经典脚本遇到脚本时暂停解析,执行完再继续
  2. defer并行下载,文档解析完后按顺序执行
  3. async并行下载,一旦可运行便执行,顺序不固定

模块脚本默认具备延后执行特性,额外写 defer 没有效果;加 async 才会改变执行时机。

核心回答

先记住这个答案

普通外部经典脚本若不加属性,浏览器遇到它时要暂停 HTML 解析,下载并执行后再继续。加 defer 可以边解析边下载,等文档解析完后按标签出现顺序执行,执行完才触发 DOMContentLoaded。加 async 也能边解析边下载,但下载就绪便尽快执行,当时若仍在解析会暂停解析;多个异步脚本没有相互执行顺序保证。依赖 DOM 或其他脚本时选 defer,独立的统计脚本更适合 async。

  • defer 在解析完成后按标签顺序执行
  • async 下载完成就执行,不保证顺序
  • defer 会延后 DOMContentLoaded
  • 内联经典脚本上的 defer 不起作用

两个脚本有依赖该怎么放

页面有一个基础库和一个用它初始化导航的脚本。第二个必须等第一个执行过,且要能找到正文里的导航节点。把两个外部经典脚本都标记为 defer,并按依赖顺序写入 HTML,就能让下载并行、执行有序。

依赖脚本用 deferHTML
<head>
  <script defer src='/js/vendor.js'></script>
  <script defer src='/js/nav.js'></script>
</head>
<body>
  <nav id='site-nav'>站点导航</nav>
</body>

vendor.js 会先于 nav.js 执行,即使后者下载得更快。两者都在文档解析完成后运行,因此 nav.js 可以查询后面的导航节点。若把两条都改成 async,加载速度决定谁先执行,基础库可能还没有准备好,页面便偶发报错。

async 为什么适合独立脚本

广告统计或独立监控脚本通常不需要访问其他脚本创建的全局对象,也不应阻止页面主体尽早解析。给这类外部脚本加 async,网络下载与文档解析并行;脚本一旦准备好就执行。代价是执行时机不固定,不能假设页面节点一定已经全部存在,也不能假设它在另一条 async 脚本之后执行。

async 的含义不是让 JavaScript 在后台线程运行。下载可以并行,但执行脚本仍会占用主线程,执行期间页面处理会受影响。如果代码依赖完整 DOM,应自己检查节点是否可用或改选更适合的加载方式。异步脚本也不参与 DOMContentLoaded 的等待:事件可能先于它执行,别把这个事件当成异步脚本已经完成的证明。

内联脚本和模块脚本的边界

defer 针对带 src 的外部经典脚本。内联经典脚本没有要并行下载的文件,写上 defer 不会把它移到解析结束后执行。模块脚本使用 type='module',默认已经延后到解析之后执行,额外写 defer 没作用;模块脚本若加 async,则按异步模块脚本的时机执行,不能沿用默认的有序等待假设。

讨论脚本性能时,先确认是经典脚本、内联脚本还是模块脚本。同样一个 <script> 标签,因为类型和属性不同,加载和执行顺序会变。项目若由打包工具注入脚本,也要检查最终生成的 HTML,而不是只凭源码中的导入语句猜浏览器时序。

回答前,多想一步

容易答错的地方

以为 defer 和 async 都只在页面加载完后执行
defer 等文档解析完成;async 只等自身下载就绪,可能在解析中途执行。两者的下载都可与解析并行,但执行时间不同。
以为 async 能保证标签顺序
async 不保证多个脚本的相对执行顺序。需要基础库先执行、业务脚本后执行时,使用 defer 并按顺序放标签,或通过模块依赖明确关系。
试着用自己的话回答

面试官还会怎么问?

defer 脚本和 DOMContentLoaded 谁先?

外部经典 defer 脚本在事件之前执行;浏览器会等它们下载并完成求值,再触发 DOMContentLoaded。所以它适合依赖已解析 DOM 的初始化代码。

async 脚本会延迟 DOMContentLoaded 吗?

不会因为自身是 async 就让这个事件等待它。事件可能在它执行前触发;脚本若要依赖该事件,应检查文档当前状态,避免监听器注册得太晚。

内联脚本写 defer 有用吗?

对没有 src 的经典内联脚本没有效果。它仍在解析器遇到的位置执行;需要延后时可改外部脚本配 defer,或选择合适的模块与事件初始化方式。

从一道题,走向一组知识

把知识连起来

语义与文档

select 选项很多时,optgroup 怎么分组?

若脚本要给 <select> 的分组选项补交互,defer 可确保查询控件时 HTML 已解析。

语义与文档

img 的 srcset 怎么根据视口和像素密度选图?

脚本的 async 与图片的 srcset 都影响资源加载,但图片候选选择不决定 JavaScript 执行顺序。

参考资料

  • HTML:语义与文档参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 两个脚本有依赖该怎么放
  3. async 为什么适合独立脚本
  4. 内联脚本和模块脚本的边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑