使用webextension-polyfill时browser.runtime.onMessage.addListener失效,报错无法建立连接
使用webextension-polyfill时browser.runtime.onMessage.addListener失效,报错无法建立连接
看起来你遇到的问题核心是webextension-polyfill对runtime.onMessage的异步处理要求和原生Chrome API略有差异,再加上你在background脚本内部给自己发消息的场景,导致消息通道提前断开了。我来帮你一步步排查修复:
1. 修复onMessage的异步响应逻辑
你的translateText是异步函数,返回的是Promise,但直接把它传给sendResponse时,没有告诉监听函数“我要异步处理结果”。不管是原生API还是webextension-polyfill,只要用异步方式调用sendResponse,都需要在监听函数末尾返回true——否则浏览器会认为你已经同步完成响应,直接关闭消息通道,后续Promise resolve时就会找不到接收端,抛出连接失败的错误。
修改你的监听代码:
browser.runtime.onMessage.addListener((message, sender, sendResponse) => { // 处理异步函数的Promise结果 translateText(message.text).then(translated => { sendResponse(translated); }); // 返回true,告诉浏览器等待异步响应 return true; });
或者用更直观的async/await写法:
browser.runtime.onMessage.addListener(async (message, sender, sendResponse) => { const translated = await translateText(message.text); sendResponse(translated); // 同样需要返回true来保持通道开放 return true; });
2. 优化background脚本的执行顺序
你的代码里先写了console.log再导入browser,虽然ES模块的import会自动提升到顶部,但为了避免潜在的加载顺序问题,建议把import语句放在最开头:
import browser from 'webextension-polyfill'; console.log('background script loaded'); // 后续的contextMenus创建、监听代码...
3. 更高效的替代方案:直接调用本地函数
其实你完全没必要通过runtime.sendMessage来调用background内部的translateText——毕竟都是同一个脚本里的函数,直接调用就能拿到结果,还能彻底避开消息传递的问题:
browser.contextMenus.onClicked.addListener(async (info, tab) => { console.log(info); console.log(tab); if (info.menuItemId === 'translate-selection') { const textToTranslate = info.selectionText; // 直接调用本地异步函数,省去消息传递环节 const response = await translateText(textToTranslate); console.log(response); } });
验证修复
按上面的方法修改后,再测试右键菜单翻译功能:
- 先确认控制台能看到
background script loaded的日志,说明脚本正常加载 - 点击右键菜单后,应该能直接输出
translated text,不会再出现连接失败的报错
备注:内容来源于stack exchange,提问作者Pluveto
相关产品推荐
相关产品推荐

