Расширение Chrome: код внутри chrome.runtime.onMessage.addListener никогда не запускается
У меня много проблем с попыткой передать переменную из сценария содержимого в 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?
Ответы
Вы не должны помещать прослушиватель событий в другой обработчик событий, это крайне плохая практика, даже если он делает то, что, по вашему мнению, должен делать, это вызовет утечку памяти для вас в будущем и затруднит чтение кода и семантически неверно.
Судя по вашему коду, проблема в том, что обработчик сообщения вызывается несколько раз из-за того, что предыдущие прослушиватели событий добавлены в событие нажатия.
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
все работает хорошо, то код, которым я поделился, должен работать