一、核心结论
chrome.runtime.sendMessage(以及旧版chrome.extension.sendMessage)是完全异步的。- 接收方(
onMessage)若包含耗时或异步操作,必须显式返回true,否则发送方会立刻收到undefined。 - 发送方获取返回数据推荐使用
async/await或Promise写法,代码更简洁直观。
二、发送方:消息发送与数据获取
发送方通过
sendMessage 发出请求,并通过回调、Promise 或 await 接收接收方返回的数据。chrome.runtime.sendMessage({ type: 'zhousavedata', data: '测试数据' }, (response) => {// response 即为接收方返回的数据console.log("获取到返回数据:", response);
});
2. Promise 写法(现代)
chrome.runtime.sendMessage({ type: 'zhousavedata', data: '测试数据' }).then((response) => {console.log("通过 Promise 获取到的数据:", response);}).catch((error) => {console.error("消息发送失败:", error);});
3. async/await 写法(强烈推荐,最简洁)
async function sendData() {try {// 像写同步代码一样等待异步返回的结果const response = await chrome.runtime.sendMessage({ type: 'zhousavedata', data: '测试数据' });console.log("通过 await 获取到的数据:", response);} catch (error) {console.error("消息发送失败:", error);} } sendData();
三、接收方:异步处理与响应通道
接收方通过
onMessage 监听消息。如果监听器内部包含异步操作(如 setTimeout、fetch、chrome.storage 等),必须保持消息通道打开。1. 错误写法(通道被提前关闭)
如果不返回
如果不返回
true,监听器函数执行完毕后 Chrome 会立刻关闭通道。后续异步操作完成时调用 sendResponse 将失效,发送方会立刻收到 undefined
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {if (request.type === 'zhousavedata') {setTimeout(() => {// 此时通道已关闭,发送方收不到此数据sendResponse({ status: 'success', msg: '保存成功' }); }, 1000);// ️ 缺少 return true } });
2. 正确写法(显式返回 true)
通过 return true 明确告知 Chrome 这是一个异步响应,请保持通道打开,等待后续的 sendResponse。
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {if (request.type === 'zhousavedata') {setTimeout(() => {sendResponse({ status: 'success', msg: '保存成功' }); }, 1000);// 关键:返回 true,声明这是一个异步响应return true; } });
3. 最佳实践(直接返回 Promise)
直接返回一个 Promise,Chrome 会自动保持通道打开,并在 Promise resolve 时将结果发回给发送方。无需手动调用 sendResponse 和 return true。
chrome.runtime.onMessage.addListener((request, sender) => {if (request.type === 'zhousavedata') {// 直接返回 Promise,resolve 的内容即为发送给请求方的数据return new Promise((resolve) => {setTimeout(() => {resolve({ status: 'success', msg: 'Promise 异步处理完毕' });}, 1000);});} });
四、常见问题排查清单
- 发送方收到
undefined:检查接收方是否在异步操作外忘记写return true,或者sendResponse被提前调用。 - 数据无法传递:检查
sendResponse或resolve传递的数据是否包含不可序列化的对象(如 DOM 节点、函数、循环引用等)。 - API 规范:现代 Chrome 插件开发中,官方推荐使用
chrome.runtime.sendMessage替代较老的chrome.extension.sendMessage。
