wake-up-neo.com

Chrome Extension Message passing: Antwort nicht gesendet

Ich versuche, Nachrichten zwischen Inhaltsskript und der Erweiterung weiterzuleiten

Hier ist, was ich in Content-Skript habe

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

Und im Hintergrundskript habe ich

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

}

Wenn ich nun die Antwort vor dem Ajax-Aufruf in der Funktion getUrls sende, wird die Antwort erfolgreich gesendet, aber in der Erfolgsmethode des Ajax-Aufrufs wird sie beim Senden der Antwort nicht gesendet, wenn ich gehe Beim Debuggen sehe ich, dass der Port im Code für die Funktion sendResponse null ist.

144
Abid

Von die Dokumentation für chrome.runtime.onMessage.addListener :

Diese Funktion wird ungültig, wenn der Ereignis-Listener zurückgibt, es sei denn, Sie geben vom Ereignis-Listener true zurück, um anzuzeigen, dass Sie eine Antwort asynchron senden möchten (dies hält den Nachrichtenkanal zum anderen Ende hin offen, bis sendResponse aufgerufen wird).

Sie müssen also nach dem Aufruf von getUrls nur noch return true; Hinzufügen, um anzuzeigen, dass Sie die Antwortfunktion asynchron aufrufen.

331
rsanchez

Die akzeptierte Antwort ist richtig. Ich wollte nur Beispielcode hinzufügen, der dies vereinfacht. Das Problem ist, dass die API (meiner Ansicht nach) nicht gut gestaltet ist, da wir Entwickler wissen müssen, ob eine bestimmte Nachricht asynchron behandelt wird oder nicht. Wenn Sie mit vielen verschiedenen Nachrichten umgehen, wird dies zu einer unmöglichen Aufgabe, da Sie nie wissen, ob eine übergebene sendResponse im Grunde genommen asynchron heißt oder nicht. Bedenken Sie:

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

Wie kann ich herausfinden, ob der Anruf im Grunde handleMethod1 Asynchron ist oder nicht? Wie kann jemand, der handleMethod1 Ändert, wissen, dass ein Anrufer durch die Einführung einer asynchronen Funktion unterbrochen wird?

Meine Lösung lautet:

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

});

Dadurch wird der Rückgabewert automatisch verarbeitet, unabhängig davon, wie Sie die Nachricht verarbeiten. Beachten Sie, dass dies voraussetzt, dass Sie nie vergessen, die Antwortfunktion aufzurufen. Beachten Sie auch, dass Chrom dies für uns hätte automatisieren können, ich verstehe nicht, warum sie dies nicht getan haben.

8
Zig Mandel

Sie können meine Bibliothek https://github.com/lawlietmester/webextension verwenden, um diese Funktion auf Chrome und FF mit Firefox-Art und Weise ohne Rückrufe auszuführen.

Ihr Code sieht folgendermaßen aus:

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