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

如何在Chrome扩展内容脚本fetch完成前暂停页面JavaScript执行?

实现Chrome扩展优先完成Fetch并暂停页面JS执行

核心思路

要实现这个需求,关键在于让内容脚本在页面所有JS之前执行,并拦截页面所有脚本的加载/执行,直到你的fetch请求完成后再恢复。

具体实现步骤

1. 配置内容脚本的注入时机

在manifest.json中设置内容脚本的run_at为document_start,确保它在页面DOM解析、任何页面JS运行之前加载:

{
  "content_scripts": [
    {
      "matches": ["<你的目标页面匹配规则>"],
      "js": ["content.js"],
      "run_at": "document_start"
    }
  ]
}

2. 拦截并缓存页面脚本

在content.js中,通过以下方式拦截所有脚本的执行:

  • 重写document.createElement,捕获外部脚本的创建请求并缓存
  • 使用MutationObserver监控DOM变化,捕获内联脚本和动态添加的脚本
  • 临时阻止脚本的执行逻辑

示例代码:

// 缓存所有待执行的脚本
const scriptQueue = [];
let isFetchCompleted = false;

// 重写document.createElement,拦截外部脚本创建
const originalCreateElement = document.createElement;
document.createElement = function(tagName) {
  if (tagName.toLowerCase() === 'script' && !isFetchCompleted) {
    const script = originalCreateElement.call(this, tagName);
    // 缓存脚本的src和属性
    scriptQueue.push({
      type: 'external',
      src: script.src,
      attributes: [...script.attributes].map(attr => ({name: attr.name, value: attr.value}))
    });
    // 返回空元素阻止原脚本加载
    return originalCreateElement.call(this, 'div');
  }
  return originalCreateElement.call(this, tagName);
};

// 使用MutationObserver拦截内联脚本和动态添加的脚本
const observer = new MutationObserver(mutations => {
  if (isFetchCompleted) return;
  mutations.forEach(mutation => {
    mutation.addedNodes.forEach(node => {
      if (node.tagName?.toLowerCase() === 'script') {
        if (node.src) {
          // 外部脚本加入队列
          scriptQueue.push({
            type: 'external',
            src: node.src,
            attributes: [...node.attributes].map(attr => ({name: attr.name, value: attr.value}))
          });
          node.remove();
        } else if (node.textContent.trim()) {
          // 内联脚本加入队列
          scriptQueue.push({
            type: 'inline',
            content: node.textContent
          });
          node.remove();
        }
      }
    });
  });
});

// 启动监控,监听整个文档的变化
observer.observe(document, { childList: true, subtree: true });

3. 执行Fetch并恢复页面脚本

发起你的fetch请求,完成后将缓存的脚本逐个恢复执行:

// 发起优先执行的fetch请求
fetch('<你的请求URL>', {
  // 你的请求配置
})
.then(response => response.json())
.then(data => {
  // 处理fetch返回的数据
  console.log('Fetch完成,数据:', data);
})
.catch(err => {
  console.error('Fetch失败:', err);
})
.finally(() => {
  isFetchCompleted = true;
  // 停止监控
  observer.disconnect();
  // 恢复document.createElement的原始逻辑
  document.createElement = originalCreateElement;
  // 执行缓存的所有脚本
  scriptQueue.forEach(script => {
    if (script.type === 'external') {
      const externalScript = document.createElement('script');
      script.attributes.forEach(attr => externalScript.setAttribute(attr.name, attr.value));
      externalScript.src = script.src;
      document.head.appendChild(externalScript);
    } else if (script.type === 'inline') {
      const inlineScript = document.createElement('script');
      inlineScript.textContent = script.content;
      document.head.appendChild(inlineScript);
    }
  });
});

注意事项

  • 这种方法可能会影响页面加载体验,页面会在fetch完成前处于无JS状态
  • 部分页面可能有特殊的脚本加载逻辑(比如动态生成脚本),需要根据实际情况调整拦截规则
  • 确保你的fetch请求尽可能高效,避免过长时间阻塞页面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 13:42:30