chrome.runtime.sendMessage回调意外返回true的问题求助
你好呀!我来帮你拆解下这个让人困惑的true返回值问题~
首先,先梳理下你的核心疑问:明明后台脚本只会返回object或undefined,但调用renderMarketItem时却偶尔拿到true,这大概率和Chrome扩展的消息机制以及你的代码调用方式有关,我整理了几个可能的原因和对应的解决思路:
可能的原因1:消息并发导致的回调错乱
你在updateConfig的消息监听里,用.each()循环同步调用了多个异步的renderMarketItem,这会一下子发起一堆chrome.runtime.sendMessage请求。Chrome的消息队列虽然是按序处理,但如果多个请求的响应回来时,可能出现回调绑定错乱的情况——比如某个不相关的消息响应(比如updateConfig自身的响应)被错误地绑定到了getMarketItem的回调上,导致你拿到了true。
解决办法:把并行调用改成串行调用,确保每个sendMessage都等上一个处理完再发起,避免消息冲突:
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => { if (message.action == 'updateConfig') { // 改用for循环+await实现串行处理 const $items = $('.items-grid').children(); for (let i = 0; i < $items.length; i++) { await renderMarketItem($($items[i])); } // 如果后台需要updateConfig的响应,这里可以按需返回 sendResponse({status: 'done'}); } // 异步处理消息时返回true,告知Chrome保留消息通道 return true; });
可能的原因2:后台消息监听的异步处理逻辑有疏漏
虽然你说后台只会返回object或undefined,但如果后台处理getMarketItem消息时,是异步操作(比如请求外部接口),那后台的监听函数需要返回true来告知Chrome“我要异步调用sendResponse,别关闭通道”。如果后台没正确调用sendResponse,或者不小心把true当成响应值传了出去,就会导致前端拿到true。
解决办法:检查后台处理getMarketItem的代码,确保:
- 异步处理时函数返回
true - 最终调用
sendResponse时传入的确实是目标item或undefined,没有误传true
可能的原因3:未处理消息发送的错误情况
如果sendMessage发送失败(比如后台脚本未加载、消息格式错误),Chrome会设置chrome.runtime.lastError,但你的代码里没处理这种情况,可能导致意外的返回值。
解决办法:在renderMarketItem里加上错误捕获和lastError检查:
async function renderMarketItem(item) { // 解析item的name, type, quality(确保这里的type/name/quality是正确获取到的哦) let market_item; try { market_item = await new Promise((resolve, reject) => { if (chrome.runtime?.id) { chrome.runtime.sendMessage({ action: "getMarketItem", name: formatData(type, name, quality) }, (response) => { // 检查消息发送是否出错 if (chrome.runtime.lastError) { reject(new Error(chrome.runtime.lastError.message)); } else { resolve(response); } }) } else { resolve(undefined); } }); } catch (err) { console.error('获取商品信息失败:', err); market_item = undefined; } // 后续逻辑 }
可以先试试这些方案,排查下问题出在哪~
备注:内容来源于stack exchange,提问作者THEMOD

