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

Chrome扩展:如何让内容脚本在网站脚本前完成执行?

问题描述

我正在开发Chrome扩展,内容脚本通过chrome.storage.local.get获取数据后执行逻辑,要求在网站脚本启动前完成全部操作。已经配置了run_at: "document_start",但chrome.storage.local.get是异步操作,耗时较长,导致内容脚本虽先启动,但完成时间晚于网站脚本。

现有manifest配置:

"content_scripts": [
  {
    "run_at": "document_start",
    "matches": ["<all_urls>"],
    "js": ["content.js"],
    "match_about_blank": true
  }
]

content.js代码:

(async () => {
   // 此时网站脚本还未执行
   let data = await chrome.storage.local.get("data");
   // 此时网站脚本已经执行了
})();
可行解决方案

1. 拦截页面脚本执行,等待数据加载完成

利用beforescriptexecute事件拦截所有页面脚本的运行,直到拿到storage数据后再恢复执行。这种方式不会阻塞主线程,而是通过事件拦截控制脚本执行时机。

修改后的content.js:

let scriptsToRun = [];
let isDataReady = false;

// 拦截所有页面脚本执行
document.addEventListener('beforescriptexecute', e => {
  if (!isDataReady) {
    e.preventDefault();
    scriptsToRun.push(e.target);
  }
});

// 加载数据后恢复脚本执行
(async () => {
  const { data } = await chrome.storage.local.get("data");
  // 这里执行你的业务逻辑
  console.log('拿到数据:', data);
  
  isDataReady = true;
  // 执行之前拦截的脚本
  scriptsToRun.forEach(script => {
    const newScript = document.createElement('script');
    newScript.textContent = script.textContent;
    newScript.src = script.src;
    script.parentNode.replaceChild(newScript, script);
  });
})();

2. 后台脚本预缓存数据,快速通信传递

把storage数据预加载到后台脚本的内存中,content script启动时直接向后台请求数据,避免直接读取storage的延迟。

  • 后台脚本background.js:
let cachedData = null;

// 初始化时加载数据到内存
chrome.storage.local.get("data", res => {
  cachedData = res.data;
});

// 监听content script的请求
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  if (msg.type === 'GET_DATA') {
    sendResponse(cachedData);
  }
  return true; // 保持通道开放直到数据准备好
});
  • 修改后的content.js:
(async () => {
  // 向后台请求预缓存的数据
  const data = await chrome.runtime.sendMessage({ type: 'GET_DATA' });
  // 执行你的业务逻辑
  console.log('拿到数据:', data);
})();

3. 通过chrome.webRequest延迟页面加载

利用chrome.webRequestAPI拦截页面的主文档请求,延迟响应直到数据准备完成。这种方式需要额外声明权限,且会影响页面加载体验,需谨慎使用。

  • 更新manifest.json:
"permissions": ["storage", "webRequest", "webRequestBlocking", "<all_urls>"],
"background": {
  "service_worker": "background.js"
}
  • 后台脚本background.js:
let isDataReady = false;
let pendingRequests = [];

// 预加载数据
chrome.storage.local.get("data", res => {
  isDataReady = true;
  // 处理延迟的请求
  pendingRequests.forEach(() => {
    chrome.webRequest.handlerBehaviorChanged(() => {
      chrome.webRequest.onBeforeRequest.removeListener(blockRequest);
    });
  });
});

// 拦截主文档请求
function blockRequest(details) {
  if (!isDataReady && details.type === 'main_frame') {
    pendingRequests.push(details);
    return { cancel: true };
  }
}

chrome.webRequest.onBeforeRequest.addListener(
  blockRequest,
  { urls: ["<all_urls>"], types: ["main_frame"] },
  ["blocking"]
);
不推荐的方案
  • 阻塞主线程:比如用while循环轮询等待数据加载,会导致页面长时间无响应,严重影响用户体验,绝对不建议使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:40:59