IE9完全不支持async且defer仅对内联脚本有效;应改用动态创建script元素并链式处理onload回调来确保加载顺序。

答案很明确:不一致。在IE9中,async属性被完全无视,而defer的表现也存在关键缺陷,远非现代浏览器那般可靠。
IE9 完全不支持 async 属性
如果你指望async在IE9里能发挥异步加载的神效,那恐怕要失望了。IE9及其更早的版本,直接将async视为一个陌生的HTML标签属性。它既不会报错,也不会触发任何异步加载逻辑。最终,所有标记了async的标签,都会退化成最原始的同步阻塞加载模式。
- 举个例子,即使你严格按标准写成
,在IE9眼里,它跟没两样——页面解析会停下来,乖乖等它下载并执行完毕。 - 更棘手的是,你无法通过简单的特性检测来安全降级。像
"async" in document.createElement("script")这种检测方法,在IE9中会返回false。但这并不能直接导向安全的备选方案,因为另一个备选defer本身也有问题。 - 这里还有一个现代开发中容易踩的坑:如果使用Webpack这类打包工具,却没有专门为IE9配置兼容模式,打包输出的脚本标签很可能自带
async,这会导致在老浏览器上出现意料之外的加载卡顿。
defer 在 IE9 中只对内联脚本“伪生效”
那么defer总该靠谱些吧?遗憾地说,它在IE9里的表现同样半生不熟。IE9确实认识defer这个语法,但其“延迟执行”的语义,仅对内联脚本有效。也就是说,只有当标签里直接包含代码(格式如)时,它才会被延迟到DOM解析完成后执行。而对于我们最常用的、带src属性的外链脚本,defer实际上形同虚设——脚本依然会按照在HTML中的出现顺序,同步下载并立即执行。
- 这是一个典型的错误期待:
。在IE9中,它并不会延迟,而是立刻下载执行。 - 有没有折中的办法?比如写成内联脚本去动态加载:
。这种做法确实能让loadScript这个函数调用被延迟执行,但你需要自己实现loadScript函数,并且依然无法依靠浏览器来保证多个脚本之间的依赖加载顺序。 - 事件监听也变得棘手。
DOMContentLoaded事件在IE9中虽然可用,但由于defer外链脚本的执行时机混乱(可能已提前执行,也可能还没触发),会导致基于此事件注册的监听器把握不准脚本的加载状态。
兼容 IE9 的实际替代方案
既然如此,在需要兼容IE9的场景下,最稳妥的办法就是彻底放弃对async和defer原生语义的依赖,转而采用由Ja vaScript显式控制的加载逻辑。核心思路就一条:将外链脚本全部转为动态注入,并通过事件回调来精细管理它们的执行顺序。
- 具体操作是,把所有通过
src引用的脚本从HTML模板中移除,统一使用document.createElement("script")的方式来创建脚本元素,设置好src属性后,再将其追加到head或body中。 - 当多个脚本存在严格的依赖关系、需要顺序执行时,可以采用链式回调。也就是在第一个脚本的
onload事件中,再去创建和加载第二个脚本,如此递进。 - 需要警惕的是,避免在
DOMContentLoaded事件处理函数中一次性注入多个无序的脚本。因为在IE9下,该事件的触发时机与脚本的实际加载完成状态没有强关联,很容易导致依赖关系出错。 - 如果项目本身采用了RequireJS或SeaJS这类AMD模块加载器,倒是一个省心的选择。不过务必确认你使用的版本明确兼容IE9(例如RequireJS的2.1.x版本),这些加载器内部已经妥善处理了原生属性的缺陷。
总的来说,IE9对脚本加载属性的支持,可以概括为“有语法,无语义”:它能读懂defer这个词,但不保证实现标准行为;至于async,则完全处于隐身状态。因此,要实现真正跨浏览器可控的脚本加载,可靠路径是利用JS动态创建配合事件驱动,而非依赖HTML标签属性。这一点在维护那些需要兼顾IE9的遗留系统时尤其关键——千万别看到标签里写着defer就高枕无忧,在IE9的世界里,它很可能还在默默阻塞着你的页面渲染。
