chrome.runtime.onMessage.addListener返回true未等待响应问题
问题根因与修复方案
代码失效和return true保持消息通道的逻辑无关,是三个实现错误叠加导致的:
chrome.notifications.onButtonClicked的回调参数顺序写反。该事件回调第一个参数是通知ID,第二个参数是用户点击的按钮序号(从0开始,0对应第一个Allow按钮,1对应第二个Block按钮),原代码把第二个参数当成通知ID做匹配,判断条件永远不成立,resp函数根本不会执行。- 事件监听器动态注册且未做清理。每次收到内容脚本消息就新增一个点击监听,既会造成内存泄漏,在Manifest V3的Service Worker后台模式下,动态注册在异步回调里的监听器会随Worker休眠被直接回收,根本等不到用户点击按钮的操作。
- 冗余的
chrome.tabs.get调用增加了不必要的异步嵌套。消息回调的sender.tab对象本身就携带了发送消息的标签页URL等信息,无需额外调用API获取。
可直接运行的修复代码
后台脚本 bg.js
注意通知点击监听必须在代码顶层全局注册一次,不要嵌套在消息监听回调内部:
// 存储通知ID与对应消息响应函数的映射关系 const notificationBindMap = new Map(); // 全局只注册一次通知按钮点击监听 chrome.notifications.onButtonClicked.addListener((notifyId, btnIndex) => { if (!notificationBindMap.has(notifyId)) return; const sendResponse = notificationBindMap.get(notifyId); // 回传用户选择结果 sendResponse({ rejected: btnIndex === 1, id: notifyId }); // 清理缓存与已处理的通知,避免内存泄漏 notificationBindMap.delete(notifyId); chrome.notifications.clear(notifyId); }); chrome.runtime.onMessage.addListener((req, sender, sendResponse) => { // 直接从sender对象取当前页面信息,无需额外调用tabs.get const currentHost = new URL(sender.tab.url).hostname; chrome.notifications.create({ type: 'basic', title: 'hi', message: 'you are on ' + currentHost, iconUrl: 'icon.png', buttons: [ { title: 'Allow' }, { title: 'Block' } ] }, (notifyId) => { // 绑定通知ID和当前消息的响应函数 notificationBindMap.set(notifyId, sendResponse); }); // 保持消息通道开放,等待异步响应 return true; });
内容脚本 content.js
原有逻辑无需修改:
chrome.runtime.sendMessage('a message', function(response) { console.log(response) })
配置注意事项
- Manifest V3版本需要在配置文件中声明
notifications权限,若要读取标签页URL,需额外声明tabs权限或对应站点的host权限。 - 不要给
onMessage的回调函数加async标记:async函数默认返回Promise,会覆盖手动return true的逻辑,导致消息通道提前关闭。 - 所有Chrome扩展事件监听器尽量在代码顶层注册,MV3的Service Worker会在闲置时自动休眠,嵌套在异步回调里动态注册的监听器会在Worker唤醒后丢失。
内容的提问来源于stack exchange,提问作者mmm107
相关产品推荐
相关产品推荐

