Chrome 扩展消息传递: 响应未发送

我试图在内容脚本和扩展之间传递消息

以下是我在内容-脚本

chrome.runtime.sendMessage({type: "getUrls"}, function(response) {
console.log(response)
});

在背景剧本里

chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.type == "getUrls"){
getUrls(request, sender, sendResponse)
}
});


function getUrls(request, sender, sendResponse){
var resp = sendResponse;
$.ajax({
url: "http://localhost:3000/urls",
method: 'GET',
success: function(d){
resp({urls: d})
}
});


}

现在,如果我在 getUrls函数的 ajax 调用之前发送响应,响应就会成功发送,但是在 ajax 调用的成功方法中,当我发送响应时,它并没有发送响应,当我进入调试时,我可以看到 sendResponse函数的代码中的端口为空。

58666 次浏览

来自 chrome.runtime.onMessage.addListener的文件:

当事件侦听器返回时,此函数将变为无效,除非您从事件侦听器返回 true,以表明希望异步发送响应(这将保持消息通道打开到另一端,直到调用 sendResponse)。

因此,您只需在调用 getUrls之后添加 return true;,以表明您将异步调用响应函数。

接受的答案是正确的,我只是想添加简化这个问题的示例代码。 问题在于 API (在我看来)设计得不好,因为它迫使我们开发人员知道某个特定消息是否会被异步处理。如果您处理许多不同的消息,这将成为一项不可能完成的任务,因为您永远不知道在内心深处是否会调用传入的 sendResponse 函数。 想想这个:

chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {
if (request.method == "method1") {
handleMethod1(sendResponse);
}

我怎样才能知道在 handleMethod1内部调用是否是异步的?修改 handleMethod1的人怎么知道引入异步会破坏调用者?

我的解决办法是:

chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) {


var responseStatus = { bCalled: false };


function sendResponse(obj) {  //dummy wrapper to deal with exceptions and detect async
try {
sendResponseParam(obj);
} catch (e) {
//error handling
}
responseStatus.bCalled= true;
}


if (request.method == "method1") {
handleMethod1(sendResponse);
}
else if (request.method == "method2") {
handleMethod2(sendResponse);
}
...


if (!responseStatus.bCalled) { //if its set, the call wasn't async, else it is.
return true;
}


});

这将自动处理返回值,而不管您选择如何处理消息。请注意,这里假设您永远不会忘记调用 response 函数。还要注意的是,铬可以为我们自动化这一点,我不明白为什么他们没有。

你可以使用我的 https://github.com/lawlietmester/webextension库在 Chrome 和 FF 中使用 Firefox,而不需要回调。

您的代码将看起来像:

Browser.runtime.onMessage.addListener( request => new Promise( resolve => {
if( !request || typeof request !== 'object' || request.type !== "getUrls" ) return;


$.ajax({
'url': "http://localhost:3000/urls",
'method': 'GET'
}).then( urls => { resolve({ urls }); });
}) );