Estensione di Chrome: il codice all'interno di chrome.runtime.onMessage.addListener non viene mai eseguito
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
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_state
fa un buon lavoro, il codice che ho condiviso dovrebbe funzionare