JS脚本加载失败如何重试

131 阅读2分钟

站点时遇到的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 或者更多的备用域名来重试,来实现脚本加载备份机制

这里就涉及到两个问题

  1. 怎么判断脚本加载失败
  2. 知道脚本加载失败后如何重试

首先我们解决第一个问题,怎么判断脚本加载失败? 在 菜鸟教程 里有这样一段介绍

image.png

🐨 可以看到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>") 这种方式

🤔 这种脚本重试的方法在工程化的项目中如何实现?