脚本加载失败如何重试
大约 2 分钟
线上的脚本在用户端加载失败,如何重试?普通的解决办法是重新加载页面: 最简单的方法是要求用户手动刷新页面。
但是这只能在用户端网络不好的情况刷新有效,若是,或者脚本本身存在问题,用户手动刷新页面可能无法解决问题。这种情况下,需要将脚本地址指向备用地址,然后进行重试。
设计难点
对于该问题实际上有以下几个方面需要进行考虑。
- 脚本加载失败如何判断?
- 脚本加载失败什么时候进行重试?
- 脚本如何重试?
解决方案
脚本加载失败如何判断?
可以通过
window.onerror
来判断脚本加载失败。但是需要做错误处理, 因为除了脚本加载错误外, 还有可能是其他错误。window.addEventListener( 'error', (e) => { // 判断是否为脚本加载错误 if (e.target.tagName !== 'SCRIPT' || e instanceof ErrorEvent) return console.log('捕获到错误', e) }, true // 捕获时生效 )
脚本加载失败什么时候进行重试?
在上述代码中, 我们使用了捕获时监听错误, 这是由于像
throw error
这样的错误是不会冒泡的, 所以需要在捕获时期进行监听。此外, 事件的监听应当在脚本加载前执行,只是因为 js 是单线程的,如果脚本先加载,产生错误便不会继续进行执行了。
脚本如何重试?
光重试还不行, 应该对脚本设置多个域名, 进行备份, 当一个脚本加载失败后, 还可以尝试加载其他域名下的同脚本。因此,可以用一个数组来保存多个脚本地址。
其次,重试过程中,还需要保证脚本发生阻塞,以防止后续加载的脚本对重试的脚本产生依赖。
最终代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>脚本加载错误</title> </head> <body> <script> const domains = ["test1new.com", "test2new.com", "test3new.com"]; const retryDomain = {}; // 重试所用域名 window.addEventListener( "error", (e) => { if (e.target.tagName !== "SCRIPT" || e instanceof ErrorEvent) return; console.log("捕获到错误", e); const url = new URL(e.target.src); const key = url.pathname; if (!(key in retryDomain)) { retryDomain[key] = 0; // 初始重试所用域名序号 } const domain = domains[retryDomain[key]]; url.host = domain; // 设置为新的域名 // 创建新的 script 标签, 但这样加载并不会产生阻塞 // const newScript = document.createElement("script"); // newScript.src = url.toString(); // document.body.insertBefore(newScript, e.target); // 使其保持阻塞 document.write(`\<script src="${url.toString()}">\</script>`) retryDomain[key] = (retryDomain[key] + 1) % domains.length; // index 增加 }, true // 冒泡捕获 ); </script> <script src="https://test1.com/test.js"></script> <script src="https://testError.com/test.js"></script> <script src="https://test3.com/test.js"></script> </body> </html>
Loading...