Расширение Chrome: код внутри chrome.runtime.onMessage.addListener никогда не запускается

Aug 18 2020

У меня много проблем с попыткой передать переменную из сценария содержимого в popup.js с помощью метода sendMessage.

Это сценарий содержимого, в котором я отправляю сообщение фоновому сценарию, который содержит количество дочерних элементов узла DOM:

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

Затем background.js прослушивает сообщение и отправляет собственное сообщение с той же переменной в popup.js:

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

В popup.js у меня есть кнопка, которая запускает некоторый код, если "incomingChatsNumber" больше 0 (у контейнера dom есть дочерние элементы):

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

Для меня странно то, что popup.js получает правильное значение, я могу даже console.log его, но как только я добавлю в него больше кода, если условно, код никогда не будет выполнен, даже если условие в порядке.

ОБНОВИТЬ:

После внесения изменений, предложенных ehab, я понял, что переменная все время "не определена" из-за асинхронной природы chrome.runtime.onMessage.addListener:

Скрипт содержимого:

  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 (здесь мне нужно использовать значение переменной 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);

Я понимаю, что моя проблема связана с тем, что API-интерфейсы chrome. * Асинхронны, поэтому chrome.runtime ... и console.log (...) будут выполняться одновременно, отсюда и ошибка. Итак, как же тогда использовать переменную latestIncomingChatsNumber внутри события по щелчку? Должен ли я сначала сохранять «latestIncomingChatsNumber» в локальное хранилище внутри chrome.runtime.onMessage.addListener?

Ответы

1 ehab Aug 18 2020 at 21:41

Вы не должны помещать прослушиватель событий в другой обработчик событий, это крайне плохая практика, даже если он делает то, что, по вашему мнению, должен делать, это вызовет утечку памяти для вас в будущем и затруднит чтение кода и семантически неверно.

Судя по вашему коду, проблема в том, что обработчик сообщения вызывается несколько раз из-за того, что предыдущие прослушиватели событий добавлены в событие нажатия.

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

Если save_button_stateвсе работает хорошо, то код, которым я поделился, должен работать