async属性仅对外部脚本(带src)生效,内联脚本添加无效;浏览器严格遵循规范忽略其属性,仍同步执行并阻塞解析,常见错误是误以为加async可避免dom访问报错。

async 属性只对带 src 的外部脚本生效
给内联 <script>init();</script> 加 async 完全无效,浏览器直接忽略。这不是 bug,是规范明确限定:async 仅作用于含 src 属性的外部脚本。
常见错误现象:<script async>document.getElementById('app')</script> 仍报 TypeError: Cannot read property 'getElementById' of null——不是属性没起效,而是压根没被识别。
-
<script async src="analytics.js"></script>✅ 正确 -
<script async>console.log(1)</script>❌ 白加 -
<script src="app.js" async="true"></script>❌async是布尔属性,不接受值
第三方脚本是否该用 async,只看它是否自包含
判断标准就两条:是否读写 DOM、是否依赖其他脚本。满足任一条件,就不能用 async。
典型可放心用 async 的场景:统计埋点(analytics.js)、广告 SDK(ad-banner.js)、错误上报(error-tracker.js)。它们只调 navigator.sendBeacon 或 fetch,不碰 document.body,失败也不影响主逻辑。
- 含
document.querySelector、addEventListener、document.write的脚本,一律禁用async - 第三方库文档没明确写“支持异步加载”,比如
clipboard.min.js,别加async -
lodash.js加了async,后面紧跟着用_.debounce就会报ReferenceError
多个第三方脚本混用 async 和 defer 时顺序失控
defer 脚本按 HTML 顺序执行,但不保证在所有 async 脚本之后运行。两者调度机制互不感知,混用等于放弃时序控制权。
典型报错:ReferenceError: $ is not defined,即使 <script defer src="jquery.js"></script> 写在前面,<script async src="plugin.js"></script> 仍可能抢先执行。
- 有依赖关系的脚本(如 jQuery → 插件),统一用
defer,并保持书写顺序 - 避免同时出现
async和defer;若必须共存,把async限定在完全无依赖的脚本上 -
<script async defer src="a.js"></script>中的defer会被现代浏览器忽略,按async行为执行
动态插入 script 是唯一可控的按需加载方式
当第三方脚本不该随页面初始加载(比如评论区滚动到底部才加载、地图点击后引入),必须用 JS 动态创建 <script></script> 元素。
关键控制点:必须先设 src,再绑定 onload 和 onerror,否则回调可能丢失;插入位置决定执行时机——插 head 里通常在 DOMContentLoaded 前执行,插 body 底部则接近 window.onload。
- 错误写法:
s.onload = () => init(); s.src = '/js/chart.js';—— 可能错过回调 - 正确写法:
s.src = '/js/chart.js'; s.onload = () => init(); document.head.appendChild(s); - 动态插入默认等效
async,不保序,也不等 DOM 就绪;如需保序或等 DOM,得手动加判断(如轮询document.readyState)
<script defer></script>,结果白加——浏览器根本不认 defer 对内联脚本的声明。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











