尽可能的自动化解决js脚本引入失败后重试
重试代码放在head所有js脚本之前
- 尽早执行:可以确保在页面主体内容加载之前,这些代码就开始执行,能够更快地进行一些初始化操作或处理。
- 优先处理逻辑:比如对脚本加载错误的处理逻辑可以提前准备好,一旦有错误发生能及时响应和处理。
- 控制页面加载顺序:有助于合理安排各种资源和行为的顺序,避免因顺序不当而产生一些异常或不符合预期的情况。
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js加载重试</title>
<script>
const standbyDomains = [
'static.test.com',
'static0.test.com',//error
'static1.test.com',//error
'static2.test.com',
'static3.test.com',//error
'static4.test.com',
];
const retryMaps = {};
window.addEventListener('error', function (e) {
if (e instanceof ErrorEvent || e.target.tagName !== 'SCRIPT') {
return;
}
let url = new URL(e.target.src);
let pathname = url.pathname;
if (!retryMaps[pathname]) {
retryMaps[pathname] = 0;
}
let index = retryMaps[pathname];
if (index >= standbyDomains.length) {
return;
}
const scriptElement = e.target;
const isDefer = scriptElement.hasAttribute('defer');
const isAsync = scriptElement.hasAttribute('async');
url.hostname = standbyDomains[index];
let newUrl = url.toString();
let scriptStr = `<script src='${newUrl}'`;
if (isDefer) {
scriptStr = ` defer></script>`;
} else if (isAsync) {
scriptStr = ` async></script>`;
} else {
scriptStr = `>`;
}
scriptStr = `</script>`;
document.write(scriptStr);
retryMaps[pathname] ;
}, true);
</script>
</head>
<body>
<script src="http://static0.test.com/1.js"></script>
<script src="http://static.test.com/2.js"></script>
<script src="http://static.test.com/3.js"></script>
</body>
</html>
知识点
standbyDomains
:定义了备用域名列表。retryMaps
:用于记录每个路径的错误次数。window.addEventListener('error',...)
:监听全局的错误事件,第三个参数设置为true
(表示事件捕获阶段触发),这样能确保更早地捕获到错误。- 当发生错误时,对错误进行分析处理,获取相关脚本信息。
- 依据错误计数切换到备用域名并构建新 URL。
- 根据原脚本的
defer
或async
属性构建合适的新脚本字符串,通过document.write
输出。 - 错误计数更新。
关于错误冒泡:
在 JavaScript 中,错误通常会从具体发生错误的元素向上冒泡,直到被捕获或到达全局。通过设置事件监听的第三个参数为 true
进行捕获阶段监听,可以在错误冒泡到全局之前就截获到它,及时进行处理,避免错误进一步传播和可能导致的不良影响。这种方式可以更全面、更早地处理脚本错误等情况,增强程序的健壮性和稳定性。
总结:这段代码主要利用事件监听在捕获阶段处理脚本加载错误,自动切换备用域名重新加载,并根据属性设置新脚本,同时利用错误冒泡的特性,在错误传播早期进行干预和处理。