Sunday面试指南

script 的 defer 和 async 有什么区别?会影响执行顺序和 DOMContentLoaded 吗?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:defer 和 async 都能异步下载脚本,有什么区别?

🙋‍♂️ 我:defer 等 HTML 解析完成再执行,async 下载好就执行。

🧑‍💻 面试官:页面先写库文件,再写依赖它的业务文件,都加 async 可以吗?

🙋‍♂️ 我:不一定,业务文件可能先下载完成。

🧑‍💻 面试官:换成 defer 就解决了吗?DOMContentLoaded 会不会等它们?如果是模块脚本,又该怎么理解?

这道题要把「下载、执行、依赖」分开。下载不阻塞解析,不代表执行顺序也有保证。

面试速答(60 秒版)

对于 HTML 中的外部经典脚本,普通 script 会暂停解析,等待下载并执行。defer 和 async 都可以让下载与 HTML 解析并行。

defer 会在文档解析完成后,按标签出现的顺序执行,并且 DOMContentLoaded 要等这些脚本执行完。async 则在脚本可执行时尽快执行,不保证多个脚本的先后顺序,DOMContentLoaded 也不会专门等它。

因此,有依赖、又需要操作已解析 DOM 的经典脚本,通常更适合 defer;独立的统计脚本可以考虑 async。模块脚本默认采用类似延后执行的方式,依赖顺序交给模块系统,不靠标签排列猜测。两种属性都不代表代码去了另一个线程,耗时执行仍然可能卡住页面。

脚本下载和执行是两件事

图:脚本下载和执行是两件事。

知识点详解:两个文件,为什么换一个属性就报错?

先看不加属性时发生了什么

假设页面有 lib.js 和 app.js,后者需要调用前者定义的函数。浏览器解析到一个普通的外部经典脚本标签时,会暂停 HTML 解析,等这个文件准备好并执行,再往下解析。

所以这种放置方式容易建立先后关系,但也可能让后面的页面结构迟迟不能被解析。浏览器的预加载扫描器可能提前发现其他资源,不过「提前下载」不会把当前脚本的执行阻塞自动消掉。

defer 保留顺序,async 让顺序取决于就绪时机

给两个脚本加 defer,浏览器可以一边下载、一边解析后面的 HTML。即使 app.js 先下载完成,它也要等待排在前面的 lib.js 执行。等到文档解析结束,两个文件按顺序运行。

换成 async,app.js 就可能先运行。此时它需要的函数还没有被定义,下载速度更快反而暴露了依赖问题。script 文档明确区分了这两种执行规则。

这里说的是解析器发现的外部经典脚本。动态创建标签、内联脚本和模块脚本有各自的规则,不能把一张经典脚本时间线套到所有情况上。

有依赖,先保证执行顺序

图:有依赖,先保证执行顺序。

DOMContentLoaded 等什么,不等什么?

DOMContentLoaded 表示文档已经完成解析,相关延后脚本也完成了执行。它不是「所有图片、所有网络请求都完成」。async 脚本也没有加入它必须等待的队伍。

假设一个 async 文件很早执行,页面底部的按钮可能还不存在;文件很晚执行,DOMContentLoaded 又可能已经发生。代码如果需要 DOM,应明确检查文档就绪状态,而不是寄希望于某次网速碰巧合适。

项目里怎么安排?

有明确依赖的现代代码,优先把依赖写成 import,让模块系统管理。有历史经典脚本时,可以用 defer 保持顺序。独立第三方代码不需要等其他库,才适合讨论 async。

验证时,给两个文件设置相反的响应延迟,记录「文件执行」「DOMContentLoaded」「load」三个时间点。多测几种速度,比只在本机刷新一次更能发现依赖错误。再看 Performance 中的长任务;属性改对了,也不会使一段长计算自动变短。

面试官继续追问

两个属性都写,会按哪个执行?

外部经典脚本同时带 async 和 defer 时,按 async 规则处理,不能当成两者优势叠加。

type=“module” 还需要 defer 吗?

模块脚本默认延后执行,defer 对它没有额外作用。加 async 会改变就绪后的执行安排;模块依赖仍由模块加载机制处理。

defer 能保证页面已经绘制了吗?

不能。解析完成、脚本执行和用户看到一次绘制,是不同的时间点。需要与绘制节奏配合,要另外考虑帧调度。

面试速记卡

  • 普通经典脚本:解析遇到它,可能等待下载与执行。
  • defer:并行下载,解析后按标签顺序执行。
  • async:并行下载,就绪后执行,不保证标签顺序。
  • DOMContentLoaded:等待相关延后脚本,不等待所有资源。
  • 边界:异步下载不等于后台线程执行。

公司面试真题

真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。

  • 腾讯 · 前端(TEG / QQ音乐 / PCG) · 暑期实习

    JavaScript 文件有哪些异步加载方式?(题意整理)

    腾讯暑期实习前端面经 + 总结 ↗
    面试记录为 2020 年 3 月;原帖编辑于 2020-04-19

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历