Extension Chrome : le code à l'intérieur de chrome.runtime.onMessage.addListener n'est jamais exécuté

Aug 18 2020

J'ai beaucoup de mal à essayer de passer une variable d'un script de contenu à popup.js en utilisant la méthode sendMessage.

Voici le script de contenu où j'envoie un message au script d'arrière-plan qui contient le nombre d'enfants d'un nœud DOM :

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

Ensuite, le background.js écoute le message et envoie lui-même un message avec la même variable au popup.js :

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

Dans le popup.js, j'ai un bouton qui déclenchera du code si le "incomingChatsNumber" est supérieur à 0 (le conteneur dom a des enfants):

  $("#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 chose étrange pour moi est que le popup.js obtient la bonne valeur, je peux même console.log, mais dès que je mets plus de code dessus, si conditionnel, le code n'est jamais exécuté même lorsque la condition est correcte.

METTRE À JOUR:

Après avoir fait les modifications suggérées par ehab, j'ai réalisé que la variable est "indéfinie" tout le temps en raison de la nature asynchrone de chrome.runtime.onMessage.addListener :

Scénario de contenu :

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

Arrière-plan.js :

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

Popup.js (c'est là que j'ai besoin d'utiliser la valeur de la variable entrantChatsNumber):

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

Je comprends que mon problème est lié au fait que les API chrome.* sont asynchrones donc Le chrome.runtime... et la console.log(...) seront exécutés en même temps, d'où l'erreur. Alors, comment utiliser la variable latestIncomingChatsNumber dans un événement on click alors ? Dois-je d'abord enregistrer "latestIncomingChatsNumber" dans le stockage local à l'intérieur de chrome.runtime.onMessage.addListener ?

Réponses

1 ehab Aug 18 2020 at 21:41

Vous ne devriez pas mettre un écouteur d'événements dans un autre gestionnaire d'événements, c'est une très mauvaise pratique même s'il fait ce que vous pensez qu'il devrait faire, cela provoquera des fuites de mémoire pour vous sur la route et rendra le code difficile à lire et sémantiquement Incorrect.

Il semble basé sur l'examen de votre code, le problème est que le gestionnaire du message est appelé plusieurs fois en raison d'écouteurs d'événements précédents ajoutés dans le clic 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
      }
  });

si save_button_statefait du bon travail, le code que j'ai partagé devrait fonctionner