Chrome Extension Messaggio che passa: risposta non inviata

Sto cercando di passare i messaggi tra lo script di contenuto e l’estensione

Ecco cosa ho in content-script

chrome.runtime.sendMessage({type: "getUrls"}, function(response) { console.log(response) }); 

E nello script di sfondo che ho

 chrome.runtime.onMessage.addListener( function(request, sender, sendResponse) { if (request.type == "getUrls"){ getUrls(request, sender, sendResponse) } }); function getUrls(request, sender, sendResponse){ var resp = sendResponse; $.ajax({ url: "http://localhost:3000/urls", method: 'GET', success: function(d){ resp({urls: d}) } }); } 

Ora se invio la risposta prima della chiamata ajax nella funzione getUrls , la risposta viene inviata correttamente, ma nel metodo di successo della chiamata ajax quando invio la risposta non la invia, quando vado nel debug posso vedere che la porta è nullo all’interno del codice per la funzione sendResponse .

Dalla documentazione di chrome.runtime.onMessage.addListener :

Questa funzione non è più valida quando il listener di eventi restituisce, a meno che non si restituisca true dal listener di eventi per indicare che si desidera inviare una risposta in modo asincrono (questo manterrà il canale del messaggio aperto all’altro fino a quando non si invierà sendResponse).

Quindi devi solo aggiungere return true; dopo la chiamata a getUrls per indicare che chiamerai la funzione di risposta in modo asincrono.

La risposta accettata è corretta, volevo solo aggiungere codice di esempio che semplifica questo. Il problema è che l’API (a mio avviso) non è ben progettata perché ci obbliga gli sviluppatori a sapere se un particolare messaggio verrà gestito asincrono o meno. Se gestisci molti messaggi diversi, questo diventa un compito imansible perché non sai mai se in profondità alcune funzioni passate in sendResponse verranno chiamate asincrone o meno. Considera questo:

 chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) { if (request.method == "method1") { handleMethod1(sendResponse); } 

Come posso sapere se in profondità handleMethod1 la chiamata sarà asincrona o no? Come può qualcuno che modifica handleMethod1 sapere che interromperà un chiamante introducendo qualcosa di asincrono?

La mia soluzione è questa:

 chrome.extension.onMessage.addListener(function (request, sender, sendResponseParam) { var responseStatus = { bCalled: false }; function sendResponse(obj) { //dummy wrapper to deal with exceptions and detect async try { sendResponseParam(obj); } catch (e) { //error handling } responseStatus.bCalled= true; } if (request.method == "method1") { handleMethod1(sendResponse); } else if (request.method == "method2") { handleMethod2(sendResponse); } ... if (!responseStatus.bCalled) { //if its set, the call wasn't async, else it is. return true; } }); 

Questo gestisce automaticamente il valore di ritorno, indipendentemente da come si sceglie di gestire il messaggio. Si noti che questo presuppone che non si dimentichi mai di chiamare la funzione di risposta. Nota anche che il cromo potrebbe averlo automatizzato per noi, non vedo perché non l’abbiano fatto.

Puoi utilizzare la mia libreria https://github.com/lawlietmester/webextension per fare in modo che funzioni sia in Chrome che in FF con Firefox senza richiami.

Il tuo codice sarà simile a:

 Browser.runtime.onMessage.addListener( request => new Promise( resolve => { if( !request || typeof request !== 'object' || request.type !== "getUrls" ) return; $.ajax({ 'url': "http://localhost:3000/urls", 'method': 'GET' }).then( urls => { resolve({ urls }); }); }) );