尽可能的自动化解决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>

QQ截图20240814171748.png
QQ截图20240814171914.png

知识点

  • standbyDomains:定义了备用域名列表。
  • retryMaps:用于记录每个路径的错误次数。
  • window.addEventListener('error',...):监听全局的错误事件,第三个参数设置为 true(表示事件捕获阶段触发),这样能确保更早地捕获到错误。

    • 当发生错误时,对错误进行分析处理,获取相关脚本信息。
    • 依据错误计数切换到备用域名并构建新 URL。
    • 根据原脚本的 deferasync 属性构建合适的新脚本字符串,通过 document.write 输出。
    • 错误计数更新。

关于错误冒泡
在 JavaScript 中,错误通常会从具体发生错误的元素向上冒泡,直到被捕获或到达全局。通过设置事件监听的第三个参数为 true 进行捕获阶段监听,可以在错误冒泡到全局之前就截获到它,及时进行处理,避免错误进一步传播和可能导致的不良影响。这种方式可以更全面、更早地处理脚本错误等情况,增强程序的健壮性和稳定性。

总结:这段代码主要利用事件监听在捕获阶段处理脚本加载错误,自动切换备用域名重新加载,并根据属性设置新脚本,同时利用错误冒泡的特性,在错误传播早期进行干预和处理。

Last modification:August 14, 2024
如果觉得我的文章对你有用,请随意赞赏