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

时间:2013-11-19 17:00:01

标签: javascript google-chrome google-chrome-extension google-chrome-app

我正在尝试在内容脚本和扩展程序

之间传递消息

以下是我在内容脚本中的内容

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调用的success方法中,它不发送响应,我进入调试我可以看到sendResponse函数的代码中的端口为空。

3 个答案:

答案 0 :(得分:325)

来自the documentation for chrome.runtime.onMessage.addListener

  

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

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

答案 1 :(得分:7)

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

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

});

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

答案 2 :(得分:1)

您可以使用我的库https://github.com/lawlietmester/webextension使用Firefox方式在Chrome和FF中完成此工作而无需回调。

您的代码如下:

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