Chrome扩展Popup与Content脚本双向通信及动态数据获取问题咨询
问题根因
- Content脚本中
chrome.runtime.onMessage.addListener被放在MutationObserver回调内,每次DOM变更都会重复注册监听器,旧监听器会一直持有历史listData的引用,导致响应Popup请求时返回过期数据 - Content脚本没有将最新的
listData存储在全局作用域,监听器无法获取每次DOM更新后的最新数据 - Popup关闭后上下文会被销毁,Content主动发送的消息无接收方,这种推送逻辑不适用Popup的临时运行场景
- Popup中
getLeadList注册的chrome.runtime.onMessage没有销毁逻辑,多次调用会导致内存泄漏,且Promise仅能resolve一次,无法响应后续更新
修复代码
1. Content.tsx 修复
// 全局存储最新的listData let latestListData: Array<any> = []; // 消息监听仅注册一次,永远返回最新的listData chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { if (request.greeting === 'hello') { sendResponse(latestListData); } // 处理Popup触发的页面刷新请求 if (request.action === 'reloadPage') { window.location.reload(); } return true; // 避免响应通道提前关闭,异步响应必须加该参数 }); // MutationObserver仅负责更新全局listData new MutationObserver(() => { const dataImage = document.getElementsByClassName('image'); const dataName = document.getElementsByClassName('name'); const dataTitle = document.getElementsByClassName('title'); const newListData: Array<any> = []; for (let x = 0; x < dataImage.length; x++) { const image = dataImage[x]?.firstElementChild?.src; const name = dataName[x]?.innerText; const title = dataTitle[x]?.firstElementChild?.innerText; const web = dataName[x]?.firstElementChild?.href; newListData.push({ image, name, title, web }); } // 覆盖更新全局数据 latestListData = newListData; }).observe(document, { subtree: true, childList: true });
2. Popup.tsx 修复
// 每次调用主动从Content拉取最新数据 getLeadList(query: Object): Promise<LeadResult[]> { return new Promise<LeadResult[]>((resolve) => { chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { chrome.tabs.sendMessage( tabs[0].id, { greeting: 'hello' }, (response) => { resolve(response || []); } ); }); }); } // 新增:主动刷新Content所在页面的方法 reloadContentPage(): Promise<void> { return new Promise((resolve) => { chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { chrome.tabs.sendMessage( tabs[0].id, { action: 'reloadPage' }, () => resolve() ); }); }); }
功能验证
- Popup每次打开调用
getLeadList都能拿到MutationObserver更新后的最新数据 - 页面滚动DOM更新后,重新打开Popup即可自动获取最新列表
- 调用
reloadContentPage即可触发Content页面刷新,效果和window.reload完全一致
内容的提问来源于stack exchange,提问作者user16691768
相关产品推荐
相关产品推荐

