2015-05-11 18 views
5


Provo a postMessage tra una WebApp e il ServiceWorker corrispondente. Il servizioWoker è stato registrato con successo e funziona fino ad ora.
Purtroppo ho notato un comportamento strano:
1. Il navigator.serviceWorker.controller è sempre nullo.
2. Sul lato ServiceWorker ho implementato postMessage questo modo:Chrome ServiceWorker postMessage

self.addEventListener('message', function (evt) { 
console.log('postMessage received', evt); 
}); 

Purtroppo il campo importante di inviare di nuovo a origine evt.origin = ““e evt.source = null non contengono i valori desiderati. Ma ricevo sempre gli evt.data inviati.

Sai come postare?

Grazie mille!
Andi

+0

Ho lo stesso problema in cui navigator.serviceWorker.controller è sempre nullo. La risposta selezionata non sembra risolvere questo problema: come lo hai risolto? –

risposta

10

Un modo per inviare una risposta da parte del lavoratore di nuovo al app controllato è mostrato in this demo e viene fatto nel modo seguente (non ho in realtà ancora testato questo, ma la demo funziona bene e il codice sembra essere d'accordo con le specifiche).

Nella pagina principale:

function sendMessage(message) { 
    // This wraps the message posting/response in a promise, which will 
    // resolve if the response doesn't contain an error, and reject with 
    // the error if it does. If you'd prefer, it's possible to call 
    // controller.postMessage() and set up the onmessage handler 
    // independently of a promise, but this is a convenient wrapper. 
    return new Promise(function(resolve, reject) { 
    var messageChannel = new MessageChannel(); 
    messageChannel.port1.onmessage = function(event) { 
     if (event.data.error) { 
     reject(event.data.error); 
     } else { 
     resolve(event.data); 
     } 
    }; 

    // This sends the message data as well as transferring 
    // messageChannel.port2 to the service worker. 
    // The service worker can then use the transferred port to reply 
    // via postMessage(), which will in turn trigger the onmessage 
    // handler on messageChannel.port1. 
    // See 
    // https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage 
    navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]); 
    }); 
} 

E nel codice operaio di servizio:

self.addEventListener('message', function(event) { 
    event.ports[0].postMessage({'test': 'This is my response.'}); 
}); 

si dovrebbe quindi essere in grado di utilizzare la promessa restituito dalla funzione sendMessage di fare quello che vuoi con la risposta proveniente dal lavoratore del servizio.

+0

Grazie mille. Questo è esattamente quello di cui avevo bisogno. Ora funziona! – user24502

+0

Come inviare un messaggio a più client? Ad esempio, nel caso del messaggio 'init' che dice che tutti gli script sono stati analizzati ed eseguiti? –

+3

C'è un modo per fare comunicazioni unidirezionali senza inviare il primo messaggio - Voglio inviare un messaggio su ogni evento "install" dal worker del servizio al client (senza che il client debba inviare il primo messaggio) –

4

@GalBracha stava chiedendo se è possibile comunicare con il client senza prima inviare un messaggio - sì !. Ecco un rapido esempio di come l'ho fatto quando ho voluto inviare un messaggio ai client quando è stata ricevuta una notifica push (non quando l'utente ha fatto clic sulla notifica, ma quando il servizio ha ricevuto l'evento):

nel tuo js client (dopo la registrazione operaio di servizio, ecc):

// navigator.serviceWorker.addEventListener('message', ...) should work too 
navigator.serviceWorker.onmessage = function (e) { 
    // messages from service worker. 
    console.log('e.data', e.data); 
}; 

nel vostro operaio di servizio, in risposta a qualche evento (forse l'installazione dell'evento): (? ovviamente)

// find the client(s) you want to send messages to: 
self.clients.matchAll(/* search options */).then((clients) => { 
    if (clients && clients.length) { 
     // you need to decide which clients you want to send the message to.. 
     const client = clients[0]; 
     client.postMessage("your message"); 
    } 

il trucco è quello di allegare il listener per l'evento messaggio al servizio oggetto ker, non l'oggetto finestra.

+1

@GalBracha: Vedi anche https://stackoverflow.com/a/35108844/271577 (se stai postando su una pagina di registrazione (non controllata), l'opzione 'includeUncontrolled' può aiutarti.) –

Problemi correlati