Estensione di Chrome: il codice all'interno di chrome.runtime.onMessage.addListener non viene mai eseguito

Aug 18 2020

Sto riscontrando molti problemi nel tentativo di passare una variabile da uno script di contenuto a popup.js utilizzando il metodo sendMessage.

Questo è lo script del contenuto in cui sto inviando un messaggio allo script in background che contiene il numero di figli di un nodo DOM:

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

Quindi background.js ascolta il messaggio e invia un messaggio stesso con la stessa variabile a popup.js:

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

Nel popup.js ho un pulsante che attiverà del codice se "incomingChatsNumber" è maggiore di 0 (il contenitore dom ha figli):

  $("#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();
      }
    });
  });

La cosa strana per me è che popup.js ottiene il valore giusto, posso persino console.log, ma non appena inserisco più codice se condizionale, il codice non viene mai eseguito anche quando la condizione è ok.

AGGIORNARE:

Dopo aver apportato le modifiche suggerite da ehab mi sono reso conto che la variabile è sempre "indefinita" a causa della natura asincrona di chrome.runtime.onMessage.addListener:

Sceneggiatura del contenuto:

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

Background.js:

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

Popup.js (Qui è dove devo usare il valore della variabile 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);

Capisco che il mio problema è legato al fatto che le API chrome.* sono asincrone, quindi chrome.runtime... e console.log(...) verranno eseguiti contemporaneamente, quindi l'errore. Quindi, come utilizzare la variabile latestIncomingChatsNumber all'interno di un evento on click? Devo prima salvare "latestIncomingChatsNumber" nella memoria locale all'interno di chrome.runtime.onMessage.addListener?

Risposte

1 ehab Aug 18 2020 at 21:41

Non dovresti inserire un listener di eventi all'interno di un altro gestore di eventi, questa è una pratica estremamente negativa anche se fa quello che pensi che dovrebbe fare, questo causerà perdite di memoria per te lungo la strada e renderà il codice difficile da leggere e semanticamente errato.

Sembra basandosi sull'osservazione del tuo codice, il problema è che il gestore del messaggio viene chiamato più volte a causa dei precedenti ascoltatori di eventi aggiunti nel click evet

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

se save_button_statefa un buon lavoro, il codice che ho condiviso dovrebbe funzionare