Chrome扩展:后台脚本发消息至内容脚本重复接收的修复方案
问题描述
我正在开发一款带可点击链接和按钮的Google Chrome扩展,需求是点击跳转按钮/链接完成页面跳转后,通过后台脚本终止扩展运行。目前遇到的问题是:后台脚本日志显示仅发送了一次消息,但内容脚本的onMessage监听器却接收到两条消息,该如何修复?
后台脚本(background.js)
chrome.webNavigation.onCompleted.addListener((details) => { chrome.tabs && chrome.tabs.query({ active: true, currentWindow: true }, () => { setTimeout(() => { const storage = chrome.storage.local; storage.get("activeProcess", (result) => { let activeProcess = Object.values(result)[0]; if (activeProcess && details.frameType === "outermost_frame") { const tabId = details.tabId; storage.get("message", (result) => { result.message.url = details.url; result.message.source = "background"; console.log("message sent"); chrome.tabs.sendMessage(tabId, result.message, (res) => { console.log(res); }); }); } }); }, 100); }); return true; });
后台日志输出:message sent
内容脚本(content.js)
chrome.runtime.onMessage.addListener(messagesListener); async function messagesListener(message, sender, response) { await processMessage(message, sender, response); } export const processMessage = async (message, sender, response) => { console.log("message received") }
内容脚本日志输出:message received message received
解决方案
问题根源
webNavigation.onCompleted重复触发:部分页面会因重定向、资源二次加载等原因多次触发该事件,即使判断了frameType === "outermost_frame",仍可能出现重复触发的情况。- 冗余异步逻辑:代码中已通过
details.tabId拿到目标标签ID,却额外调用chrome.tabs.query,多余的异步回调会增加逻辑混乱的概率。 - 无重复处理标记:未对已发送消息的标签做状态标记,导致后续触发的事件再次发送相同消息。
修复步骤
1. 优化后台脚本逻辑,避免重复发送
移除冗余的chrome.tabs.query和setTimeout,添加标签处理状态标记:
// 存储已处理过的标签ID,避免重复发送消息 const processedTabs = new Set(); chrome.webNavigation.onCompleted.addListener((details) => { // 过滤非外层框架或已处理的标签 if (details.frameType !== "outermost_frame" || processedTabs.has(details.tabId)) { return; } const storage = chrome.storage.local; storage.get("activeProcess", (result) => { let activeProcess = Object.values(result)[0]; if (activeProcess) { const tabId = details.tabId; storage.get("message", (result) => { result.message.url = details.url; result.message.source = "background"; console.log("message sent"); chrome.tabs.sendMessage(tabId, result.message, (res) => { console.log(res); // 标记该标签已处理 processedTabs.add(tabId); // 标签关闭时清除标记,释放内存 chrome.tabs.onRemoved.addListener((removedTabId) => { processedTabs.delete(removedTabId); }); }); }); } }); }, { // 可选:限制监听HTTP/HTTPS页面,减少无效触发 url: [{ schemes: ["http", "https"] }] });
2. 内容脚本添加去重逻辑(可选)
如果仍存在重复接收情况,可在内容脚本中根据消息标识去重:
const receivedMessages = new Set(); chrome.runtime.onMessage.addListener(async (message, sender, response) => { // 用URL+来源作为消息唯一标识 const messageKey = `${message.url}-${message.source}`; if (receivedMessages.has(messageKey)) { return; } receivedMessages.add(messageKey); await processMessage(message, sender, response); }); export const processMessage = async (message, sender, response) => { console.log("message received"); }
内容的提问来源于stack exchange,提问作者Pavel Smith
相关产品推荐
相关产品推荐

