脚本加载失败时需显式绑定onerror事件并返回false,用document.createElement动态插入带版本哈希的备用脚本,内联脚本无onerror需try/catch,外部脚本应设crossorigin="anonymous",通过缓存document.currentScript或data属性定位失败源,fallback前须检查全局状态防重复执行。

脚本加载失败时如何触发回退逻辑
脚本回退不是浏览器自动行为,必须由开发者显式控制。当 script 标签加载失败(如 404、CORS、网络中断),onerror 事件会触发,但默认不阻止后续执行或降级——你得自己写 fallback 路径。
- 必须给
<script>加onerror处理器,且返回false阻止默认错误冒泡(部分旧浏览器需要) - 避免在
onerror里直接document.write,它会清空当前文档;改用document.createElement('script')动态插入备用地址 - 备用脚本路径建议带版本哈希(如
fallback.v2.1.0.min.js),防止缓存污染 - 若主脚本含关键初始化逻辑(如路由挂载),fallback 脚本需提供最小兼容 API,否则页面功能断裂
内联脚本与外部脚本的回退差异
内联脚本(<script>...</script>)无加载失败事件,一旦语法错误或执行异常,整个 block 中断,无法靠 onerror 捕获;而外部脚本(<script src="..."></script>)可监听加载失败,但执行时异常仍需 window.onerror 兜底。
- 内联脚本只能靠
try/catch包裹逻辑,且无法捕获异步回调里的错误 - 外部脚本推荐加
crossorigin="anonymous",否则跨域错误会变成Script error.,丢失堆栈信息 - 多个外部脚本串联依赖时(如 A → B → C),B 失败后 C 不会自动跳过;需在 B 的
onerror中主动移除 C 的script标签,避免静默阻塞 -
defer和async属性影响执行时机,但不影响onerror触发逻辑——只要加载失败,无论是否 defer,都会触发
如何用 document.currentScript 定位失败脚本
document.currentScript 在脚本执行期间指向当前正在运行的 <script> 元素,是唯一能精准识别“哪个脚本出问题”的原生方式;但它在 onerror 里不可靠——因为错误发生时该脚本可能已结束执行或未开始。
- 安全做法:在每个外部脚本开头立即读取并缓存
document.currentScript,例如:const self = document.currentScript; self.dataset.loaded = 'false'; // 后续成功后设为 'true'
- 不要依赖
self.src做路径判断——CDN 重定向或 service worker 拦截后,src可能与实际加载地址不一致;改用self.getAttribute('data-src')存原始地址 - 多个同名脚本(如不同环境打包产物)共存时,仅靠
src无法区分;需配合data-env或data-chunk自定义属性 -
document.currentScript在模块脚本(type="module")中始终为null,此时应改用import.meta.url
回退后如何避免重复执行或状态冲突
脚本回退常伴随重试或切换资源,但若原始脚本已部分执行(如注册了全局变量、绑定了事件、修改了 DOM),fallback 脚本再执行就可能引发冲突或重复初始化。
立即学习“前端免费学习笔记(深入)”;
- 在主脚本入口加防重机制:
if (window.__APP_INITIALIZED__) return; window.__APP_INITIALIZED__ = true; // 初始化逻辑
- fallback 脚本不应假设主脚本完全没执行——要检查关键副作用是否存在(如
if (!window.Router) { initRouter(); }) - 避免在回退逻辑里调用
location.reload(),它会丢弃所有内存状态;优先用脚本级重置(如清空localStorage中的临时标记、重置history.state) - SPA 场景下,若路由已由主脚本接管,fallback 脚本需确认当前路由状态是否有效,否则可能跳转到错误页面
Promise,但主逻辑没跑完)。这时候 fallback 不是“换一个脚本”,而是“在残缺基础上补全”。



















