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

如何使用MutationObserver检测脚本是否已加载?

解决脚本加载检测问题(兼容已加载状态)

首先明确:MutationObserver本身不直接监听脚本的onload事件,但可以结合脚本的readyState属性,实现「不管脚本是已加载完成,还是后续插入DOM」都能触发回调的需求,同时替换掉废弃的DOMNodeInserted事件,解决控制台警告。

实现思路与步骤

  1. 先检查已存在的脚本:查询目标脚本,若已存在则判断其加载状态——若已加载(readyState为loaded或complete),直接执行回调;若未加载,添加load事件监听。
  2. 用MutationObserver监听脚本插入:监听整个文档的元素插入操作,当匹配到目标src的脚本时,重复第一步的判断逻辑。
  3. 避免重复触发:给已处理过的脚本标记自定义属性,防止同一脚本多次触发回调。
  4. 清理资源:在Lit元素断开DOM时,断开观察者避免内存泄漏。

适配Lit Element的完整代码

// 在组件类中添加属性
private disconnectObserver?: () => void;

connectedCallback() {
  super.connectedCallback();
  const targetSrc = highlightCore();
  
  // 定义脚本加载完成后的处理逻辑
  const handleScriptLoad = (script: HTMLScriptElement) => {
    console.log(`Highlighter.js script loaded`);
    console.log('Script loaded: ' + script.getAttribute('src'));
    // 这里添加你的业务逻辑
    script.dataset.processed = 'true'; // 标记已处理,避免重复触发
  };

  // 1. 检查页面中已存在的目标脚本
  const existingScript = document.querySelector(`script[src="${targetSrc}"]`);
  if (existingScript) {
    if (existingScript.dataset.processed) return;
    // 判断脚本是否已加载完成
    if (existingScript.readyState === 'loaded' || existingScript.readyState === 'complete') {
      handleScriptLoad(existingScript);
    } else {
      existingScript.addEventListener('load', () => handleScriptLoad(existingScript));
    }
  }

  // 2. 初始化MutationObserver监听新插入的脚本
  const observer = new MutationObserver((mutations) => {
    mutations.forEach(mutation => {
      mutation.addedNodes.forEach(node => {
        if (node.nodeName === 'SCRIPT' && (node as HTMLScriptElement).src === targetSrc) {
          const script = node as HTMLScriptElement;
          if (script.dataset.processed) return;
          if (script.readyState === 'loaded' || script.readyState === 'complete') {
            handleScriptLoad(script);
          } else {
            script.addEventListener('load', () => handleScriptLoad(script));
          }
        }
      });
    });
  });

  // 配置监听规则:监听整个文档树的元素插入
  observer.observe(document.documentElement, {
    childList: true,
    subtree: true
  });

  // 保存断开观察者的方法,用于组件销毁时清理
  this.disconnectObserver = () => observer.disconnect();
}

disconnectedCallback() {
  super.disconnectedCallback();
  // 组件从DOM移除时,断开观察者防止内存泄漏
  if (this.disconnectObserver) {
    this.disconnectObserver();
  }
}

关键细节说明

  • 兼容已加载脚本:脚本加载完成后,readyState会变为loaded或complete(不同浏览器表现略有差异,需同时判断),此时无需等待load事件,直接执行回调。
  • 替换废弃事件:用MutationObserver的childList+subtree监听,完全替代DOMNodeInserted,解决控制台的 deprecation 警告。
  • 避免重复触发:通过自定义data-processed属性标记已处理的脚本,确保同一脚本不会多次触发回调逻辑。
  • 内存泄漏防护:在disconnectedCallback中主动断开观察者,符合Lit组件的生命周期规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:12:42