站点时遇到的JS脚本加载失败时,会导致页面功能不完整甚至无法显示。引入失败的原因可能多种多样,导致用户流失,那有没有一种自动化的解决办法:当JS脚本加载失败时尝试使用备用域名进行重试
<!DOCTYPE html>
<html lang="zh">
<head>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body></body>
</html>
如上面这段代码,当https://unpkg.com/vue@3
加载失败时,如何用https://cdn.jsdelivr.net/npm/vue@3
或者更多的备用域名来重试,来实现脚本加载备份机制
这里就涉及到两个问题
- 怎么判断脚本加载失败
- 知道脚本加载失败后如何重试
首先我们解决第一个问题,怎么判断脚本加载失败? 在 菜鸟教程 里有这样一段介绍
🐨 可以看到script 标签是支持onerror事件的,理论上支持onerror事件的标签都可以采用本文讲的这种方式重试加载,那我们写段代码测一下,看看能不能判断加载失败
<!DOCTYPE html>
<html lang="zh">
<head>
<script>
// 资源加载错误监听(图片、脚本、CSS等)
window.addEventListener( "error", function (event) {
if (event.target instanceof HTMLElement) {
console.log("资源加载错误:", {
tagName: event.target.tagName, // 标签名
type: event.target.type, // 类型
src: event.target.src || event.target.href, // 资源地址
timeStamp: event.timeStamp, // 时间戳
});
}
},
true
);
</script>
<script src="https://dd.com/a.js"></script>
</head>
<body></body>
</html>
📢 上面代码要注意 : addEventListener 的第二要参数设置成true
,意思是开启事件捕获
,script标签上的onerror 事件是不支持冒泡的,在冒泡阶段是获取不到错误信息的,要在冒泡的前一个阶段:捕获,获取错误信息,更多知识可以查关键词:‘浏览器事件模型 冒泡 捕获’。
🚶下一步就是解决如何重试,重试时需要注意📢加载备用脚本时一定要阻塞浏览器继续执行,因为后面加载的脚本可能依赖,这个加载失败的脚本
<!DOCTYPE html>
<html lang="zh">
<head>
<script>
let urls = [
"https://dd1.com/a.js",
"https://dd2.com/a.js",
"https://dd3.com/a.js",
];
// 当前尝试的URL索引
let currentUrlIndex = 0;
// 尝试加载备用脚本
function tryBackupScript() {
if (currentUrlIndex < urls.length) {
document.write(`<script src="${urls[currentUrlIndex]}"><\/script>`);
currentUrlIndex++;
} else {
console.error("所有备用脚本都已尝试完毕");
}
}
// 资源加载错误监听(图片、脚本、CSS等)
//调用tryBackupScript加载备用脚本时如果加载不成功依然会走到error事件
window.addEventListener(
"error",
function (event) {
if (event.target instanceof HTMLScriptElement) {
console.log("脚本加载错误:", event.target.src);
// 如果是初始脚本加载失败,开始尝试备用地址
if ([...urls, "https://dd.com/a.js"].includes(event.target.src)) {
tryBackupScript();
}
}
},
true
);
</script>
<script src="https://dd.com/a.js"></script>
<script src="https://dd.com/kkk.js"></script>
</head>
<body></body>
</html>
❎ 错误的加载备份脚本的方式:
const script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
🕐 一定要用 document.write("<script src='xx'></script>")
这种方式
🤔 这种脚本重试的方法在工程化的项目中如何实现?