You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何判断script脚本是否加载完成并生成对应状态的Promise

检测Script标签加载状态的可靠实现

该方案不需要依赖「所有动态脚本由自己管控」「静态脚本按顺序执行」这类强假设,兼容静态引入、动态插入的所有带src的外部脚本、内联脚本,直接返回符合预期的Promise实例。

核心判断规则

  • 内联脚本(无src属性):只要存在于DOM树中就必然已经加载执行完成,直接返回已兑现的Promise
  • 外部脚本:
    • 优先通过Performance API判断资源是否已经完成加载:如果对应src的资源条目存在,说明脚本已经加载完成
    • 如果未查询到对应资源条目,说明脚本仍在加载/待加载,为其绑定load/error事件,在事件触发时兑现Promise
    • 兼容Performance API不可用的极端场景:绑定事件后通过setTimeout+readyState检查做兜底,避免事件漏触发

实现代码

/**
 * 获取指定script标签加载完成的Promise
 * @param {HTMLScriptElement} scriptEl 目标script标签
 * @returns {Promise<void>} 脚本加载完成时兑现,加载失败时抛出错误
 */
function getScriptLoadPromise(scriptEl) {
  if (!(scriptEl instanceof HTMLScriptElement)) {
    return Promise.reject(new TypeError('Target must be a HTMLScriptElement'));
  }

  // 内联脚本无外部资源,直接返回已兑现状态
  if (!scriptEl.src) {
    return Promise.resolve();
  }

  // 优先通过性能接口判断是否已完成加载
  if (window.performance && typeof performance.getEntriesByName === 'function') {
    const loadedEntries = performance.getEntriesByName(scriptEl.src);
    if (loadedEntries.length > 0) {
      return Promise.resolve();
    }
  }

  // 未命中已加载判断,走事件监听逻辑
  return new Promise((resolve, reject) => {
    let handled = false;

    const onLoad = () => {
      if (handled) return;
      handled = true;
      scriptEl.removeEventListener('load', onLoad);
      scriptEl.removeEventListener('error', onError);
      resolve();
    };

    const onError = () => {
      if (handled) return;
      handled = true;
      scriptEl.removeEventListener('load', onLoad);
      scriptEl.removeEventListener('error', onError);
      reject(new Error(`Script load failed: ${scriptEl.src}`));
    };

    scriptEl.addEventListener('load', onLoad);
    scriptEl.addEventListener('error', onError);

    // 兜底逻辑:兼容性能接口不可用、绑定监听前脚本刚完成加载的极端场景
    let checkCount = 0;
    const fallbackCheck = () => {
      if (handled) return;
      checkCount++;
      // 兼容旧IE的script readyState判断
      if (scriptEl.readyState === 'loaded' || scriptEl.readyState === 'complete') {
        onLoad();
        return;
      }
      // 最多轮询10次共2秒,超时直接兑现避免永久pending
      if (checkCount >= 10) {
        onLoad();
        return;
      }
      setTimeout(fallbackCheck, 200);
    };
    setTimeout(fallbackCheck, 0);
  });
}

使用方式

直接遍历document.getElementsByTagName("script")返回的集合,对每个脚本调用该方法即可,可搭配Promise.all等待所有脚本加载完成后执行后续逻辑:

const allScripts = Array.from(document.getElementsByTagName('script'));
Promise.all(allScripts.map(script => getScriptLoadPromise(script)))
  .then(() => {
    // 所有脚本加载完成后执行的逻辑
    console.log('All scripts loaded');
  })
  .catch(err => {
    console.error('Script load error:', err);
  });

边界说明

  • 跨域无Timing-Allow-Origin响应头的脚本,Performance API不会返回详细加载耗时,但资源条目本身依然存在,不影响已加载状态判断
  • 动态插入后尚未进入加载队列的脚本,事件监听逻辑会正常等待加载完成触发
  • data:协议的内联外部脚本、blob协议脚本,加载速度极快时会优先触发load事件,不会出现状态判断错误

内容的提问来源于stack exchange,提问作者Gunther Schadow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:24:16