Use MessageChannel to respond to a postMessage call
When you have a web worker or an IFrame, the communication is limited to postMessage
calls. This is due to the fact that they run in a different context and the browser needs to make sure that calls are asynchronous and only cloneable data can be sent through.
The other party is likely to expect a message, and it might want to respond to it. For example, a web worker that does some background calculations on some arguments and responds with the result.
To instantiate the worker and call it with some data, use:
var myWorker = new Worker('worker.js');
myWorker.postMessage(5);
And the worker can use the passed argument from the event:
self.addEventListener("message", (event) => {
const arg = event.data; // 5
}, false)
And it can respond with another postMessage
.
But what if multiple concurrent calls are using this single worker? In that case, the global onmessage
handler does not know which call the response belongs to. You then need some kind of request ID handling to demultiplex the messages.
Use MessageChannel
MessageChannel
is a relatively new API that can be passed through a postMessage
call to provide a unique channel that can be used for result messages.
To make a new channel, pass it to the worker, and then listen to the result, use:
const channel = new MessageChannel();
myWorker.postMessage(5, [channel.port2]);
channel.port1.onmessage = ({data}) => {
console.log(data);
}
On the worker side, use event.ports[0]
to post the response to:
event.ports[0].postMessage(event.data * 2);
This correctly handles result messages and makes the worker safe to call from muliple sources parallelly.