Transmisión de mensajes de extensión de Chrome: respuesta no enviada

Resuelto Abid asked hace 10 años • 3 respuestas

Estoy intentando pasar mensajes entre el script de contenido y la extensión.

Esto es lo que tengo en content-script

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

Y en el script de fondo tengo

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

}

Ahora si envío la respuesta antes de la llamada ajax en la getUrlsfunción, la respuesta se envía exitosamente, pero en el método de éxito de la llamada ajax cuando envío la respuesta no la envía, cuando entro en depuración puedo ver eso el puerto es nulo dentro del código de la sendResponsefunción.

Abid avatar Nov 20 '13 00:11 Abid
Aceptado

De la documentación parachrome.runtime.onMessage.addListener :

Si desea utilizar sendResponse() de forma asincrónica, agregue return true; al controlador de eventos onMessage.

Por lo tanto, solo necesita agregar return true;después de la llamada getUrlspara indicar que llamará a la función de respuesta de forma asincrónica.

Tenga en cuenta que esto no se menciona en otra documentación (por ejemplo, la onMessagedocumentación ), por lo que es posible que los desarrolladores lo pasen por alto.

rsanchez avatar Nov 19 '2013 17:11 rsanchez

La respuesta aceptada es correcta, solo quería agregar un código de muestra que simplifique esto. El problema es que la API (en mi opinión) no está bien diseñada porque nos obliga a los desarrolladores a saber si un mensaje en particular se manejará de forma asíncrona o no. Si maneja muchos mensajes diferentes, esto se convierte en una tarea imposible porque nunca se sabe si en el fondo alguna función un sendResponse pasado se llamará asíncrono o no. Considera esto:

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

¿Cómo puedo saber si en el fondo handleMethod1la llamada será asíncrona o no? ¿Cómo puede alguien que modifica handleMethod1saber que interrumpirá a la persona que llama al introducir algo asíncrono?

Mi solución es esta:

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

});

Esto maneja automáticamente el valor de retorno, independientemente de cómo elija manejar el mensaje. Tenga en cuenta que esto supone que nunca olvidará llamar a la función de respuesta. También tenga en cuenta que Chromium podría haber automatizado esto para nosotros, no veo por qué no lo hicieron.

Zig Mandel avatar May 02 '2014 17:05 Zig Mandel