Extensión de Chrome: el código dentro de chrome.runtime.onMessage.addListener nunca se ejecuta

Aug 18 2020

Tengo muchos problemas para intentar pasar una variable de un script de contenido a popup.js usando el método sendMessage.

Este es el script de contenido donde estoy enviando un mensaje al script de fondo que contiene la cantidad de elementos secundarios de un nodo DOM:

let incomingChatsNumber = incomingChatsContainer.children().length;
chrome.runtime.sendMessage({ incomingChatsNumber: incomingChatsNumber });

Luego, background.js escucha el mensaje y envía un mensaje con la misma variable a popup.js:

chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
  let incomingChatsNumber = message.incomingChatsNumber;
  chrome.runtime.sendMessage({ incomingChatsNumber: incomingChatsNumber });
});

En el popup.js tengo un botón que activará algún código si el "IncomingChatsNumber" es mayor que 0 (el contenedor dom tiene hijos):

  $("#js-toggleSorting").on("click", function () {
    chrome.runtime.onMessage.addListener(function (message) {
      let incomingChatsNumber = message.incomingChatsNumber;
      if (incomingChatsNumber <= 0) {
        $(".message").html("<p>No Chats To Sort, You Joker</p>");
      } else {
        $(".message").html("<p>Sorting Chats</p>");
        //This code never gets executed
        if ($("#js-toggleSorting").attr("data-click-state") == 1) {
          $("#js-toggleSorting").attr("data-click-state", 0);
          $("#js-toggleSorting").html("SORT INCOMING CHATS");
          sortFunction(false);
        } else {
          $("#js-toggleSorting").attr("data-click-state", 1);
          $("#js-toggleSorting").html("STOP SORTING INCOMING CHATS");
          sortFunction(true);
        }
        save_button_state();
      }
    });
  });

Lo extraño para mí es que popup.js obtiene el valor correcto, incluso puedo consolarlo. Iniciar sesión, pero tan pronto como pongo más código en eso, si es condicional, el código nunca se ejecuta, incluso cuando la condición está bien.

ACTUALIZAR:

Después de hacer las modificaciones sugeridas por ehab, me di cuenta de que la variable está "indefinida" todo el tiempo debido a la naturaleza asíncrona de chrome.runtime.onMessage.addListener:

Guión de contenido:

  let incomingChatsNumber = incomingChatsContainer.children().length;
  chrome.runtime.sendMessage({ incomingChatsNumber: incomingChatsNumber });

Fondo.js:

chrome.runtime.onMessage.addListener(function (message) {
  let incomingChatsNumber = message.incomingChatsNumber;
  chrome.runtime.sendMessage({ incomingChatsNumber: incomingChatsNumber });
});

Popup.js (Aquí es donde necesito usar el valor de la variable incomingChatsNumber):

  let latestIncomingChatsNumber;

  chrome.runtime.onMessage.addListener(function (message) {
    let incomingChatsNumber = message.incomingChatsNumber;
    latestIncomingChatsNumber = incomingChatsNumber;
    //This Works
    console.log(latestIncomingChatsNumber);
  });
  //This will give me an undefined value
  console.log(latestIncomingChatsNumber);

Entiendo que mi problema está relacionado con el hecho de que las API de chrome.* son asíncronas, por lo que chrome.runtime... y console.log(...) se ejecutarán al mismo tiempo, de ahí el error. Entonces, ¿cómo usar la variable LatestIncomingChatsNumber dentro de un evento de clic? ¿Tengo que guardar primero "latestIncomingChatsNumber" en el almacenamiento local dentro de chrome.runtime.onMessage.addListener?

Respuestas

1 ehab Aug 18 2020 at 21:41

No debe colocar un detector de eventos dentro de otro controlador de eventos, esta es una práctica extremadamente mala, incluso si hace lo que cree que debería estar haciendo, esto causará pérdidas de memoria en el futuro y hará que el código sea difícil de leer y semánticamente. incorrecto.

Al mirar su código, parece que el problema es que el controlador del mensaje recibe varias llamadas debido a los detectores de eventos anteriores agregados en el evento de clic.

 let latestIncomingChatsNumber
 chrome.runtime.onMessage.addListener(function (message) {
      let incomingChatsNumber = message.incomingChatsNumber;
      // save this into the application state, i will use a parent scope variable you could use something else 
       latestIncomingChatsNumber = incomingChatsNumber
    });
    
 $("#js-toggleSorting").on("click", function () {
      if (latestIncomingChatsNumber <= 0) {
        $(".message").html("<p>No Chats To Sort, You Joker</p>");
      } else {
        $(".message").html("<p>Sorting Chats</p>");
        //This code never gets executed
        if ($("#js-toggleSorting").attr("data-click-state") == 1) {
          $("#js-toggleSorting").attr("data-click-state", 0);
          $("#js-toggleSorting").html("SORT INCOMING CHATS");
          sortFunction(false);
        } else {
          $("#js-toggleSorting").attr("data-click-state", 1);
          $("#js-toggleSorting").html("STOP SORTING INCOMING CHATS");
          sortFunction(true);
        }
        save_button_state(); // i believe this function saves the attributes to the dom elements
      }
  });

si save_button_statehace un buen trabajo, el código que compartí debería funcionar