优先选 defer:脚本需读 dom 或有依赖时,defer 保证 dom 完整且按序执行;async 仅适用于无 dom 依赖的独立任务(如埋点),但不保序且执行时机不可控。

选 defer 还是 async,不看文档风格,只看脚本是否读 DOM、是否被其他脚本依赖、是否允许“插队”执行——这三点能直接决定页面白屏、报错或功能失效。
脚本要访问 document.getElementById 或 querySelector?必须用 defer
常见错误现象:document.getElementById("app") 返回 null,addEventListener 绑定失败,jQuery 插件报 $ is not defined。根本原因不是代码写错,而是脚本在 DOM 尚未生成时就执行了。
-
async脚本可能在标签都还没解析到时就执行,此时document.body都是undefined -
defer严格保证执行时机:HTML 解析完成、DOMContentLoaded触发前,DOM 树已完整可用 - 即使脚本体积很小、下载极快,
async依然不可靠——执行时机由网络和资源调度决定,不是开发者可控的
多个外部脚本有加载顺序依赖?只能用 defer,且顺序不能错
使用场景:先加载 lodash.js,再加载依赖它的 utils.js;或先载入 jquery.js,再载入 bootstrap.js。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
-
async不保序:哪怕jquery.js在 HTML 中写在前面,只要bootstrap.js下载更快,它就会先执行,直接报jQuery is not defined -
defer按 HTML 中的书写顺序执行,与下载完成时间无关——后声明的脚本即使先下完,也会等前面的执行完再运行 - 注意:
defer只对带src的外部脚本生效;<script defer>console.log("hi")</script>中的defer会被浏览器忽略
脚本只做上报、埋点、广告加载?优先用 async
典型表现:内部只调用 navigator.sendBeacon、fetch 或第三方 SDK 的初始化函数,不读取任何 DOM 节点,也不暴露全局变量供其他脚本调用。
-
async执行越早越好——统计脚本晚 1 秒上报,可能漏掉首屏跳出用户 - 但别把体积大的主逻辑脚本(如
main.js)设为async:它下载完会立刻中断 HTML 解析,拖慢首屏渲染 -
async在 IE10 及以下不支持,如果还要兼容老版本,得 fallback 到动态创建script元素的方式
defer 和 async 不能共存,且都禁用 document.write
容易被忽略的硬约束:
- 浏览器遇到
<script async defer src="a.js"></script>会按规范优先处理async,defer被忽略——两者语义冲突,不能同时写 -
document.write在defer/async脚本中会直接抛错,现代项目基本不用,但某些老 SDK 可能还藏着它 - 加了
defer不代表万事大吉:如果脚本里用了import()动态导入,后续模块的加载和执行不受defer约束,得靠代码自己控制加载时机
最常漏掉的一点:很多人以为加了 defer 就等于“安全”,但只要脚本里有一行 import("./feature.js"),那个 feature.js 的加载时机就脱离了 defer 的管控范围——这部分必须手动监听或兜底处理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










