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})
    }
  });

}

现在,如果我在函数中的ajax调用之前发送响应,则响应已成功发送,但是在ajax调用的成功方法中,当我发送响应时,它不会发送它,当我进行调试时,我可以看到函数代码中的端口为null。getUrlssendResponse


答案 1

来自 chrome.runtime.onMessage.addListener 的文档

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

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


答案 2

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

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

我如何知道在内心深处的呼叫是否会异步?修改的人怎么知道它会通过引入异步内容来破坏调用方?handleMethod1handleMethod1

我的解决方案是这样的:

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;
    }

});

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