Chrome扩展popup与content-script通信报错:消息端口提前关闭
问题分析与修复方案
错误原因
这个报错的核心原因是:你给chrome.runtime.onMessage的回调加了async关键字,导致回调变成了异步函数。Chrome的消息传递机制有个规则:
- 如果回调是同步执行的,会等待你调用
sendResponse后再关闭消息端口; - 但如果是异步函数(用了
async/await),Chrome会默认在函数返回Promise后立刻关闭端口,而你的await chrome.storage.local.get还没执行完,端口就已经关闭,popup那边自然收到「消息端口在收到响应前关闭」的错误。
你之前尝试加return true或sendResponse无效,大概率是位置不对——return true必须在同步阶段返回,用来告诉Chrome要等待异步的sendResponse调用,而不是放在await之后的异步代码里。
修复方法
方法一:同步返回true + 异步完成后调用sendResponse
修改content-script.js:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { console.log(request); if(request.go) { // 用立即执行异步函数包裹逻辑,避免把整个回调变成async (async () => { const go = await chrome.storage.local.get('something'); console.log(go); // 异步操作完成后调用sendResponse返回结果 sendResponse({status: 'success', data: go}); })(); // 必须在同步阶段返回true,告诉Chrome等待异步的sendResponse return true; } });
同时优化popup.js为Promise风格调用(更适配async/await):
document.getElementById('go').addEventListener('click', async () => { let [tab] = await chrome.tabs.query({active: true, currentWindow: true}); try { const response = await chrome.tabs.sendMessage(tab.id, {go: true}); console.log('通信成功', response); } catch (err) { console.log('通信失败', err); } });
方法二:直接使用异步回调(Chrome 88+支持)
如果你的目标Chrome版本在88及以上,可以直接把onMessage的回调写成async函数,此时不需要return true,只需确保回调返回的Promise最终resolve一个值:
chrome.runtime.onMessage.addListener(async (request, sender) => { console.log(request); if(request.go) { const go = await chrome.storage.local.get('something'); console.log(go); // 返回响应数据,Promise会自动resolve这个值 return {status: 'success', data: go}; } });
popup.js同样用上面的Promise风格调用即可。
内容的提问来源于stack exchange,提问作者kodfire
相关产品推荐
相关产品推荐

