22
Making web workers more accessible with closures and Promises
If you're like me, you'll find the web workers API quite hard to use at times, because of all the event handlers.
Here's some sample code:
// main.js
const worker = new Worker(workerfile)
worker.onmessage = function(e) {
doStuff(e.data)
}
It's hard to coordinate other tasks with worker messages only using this API. For example, how would you return the result of a worker calculation from a function? At first, there's no obvious easy way to do so.
Thankfully, there's a clean way around this, which wraps message handlers in a Promise.
// main.js
const worker = new Worker(workerfile)
let outsideResolve, outsideReject
const promise = new Promise((resolve, reject) => {
outsideResolve = resolve
outsideReject = reject
}
worker.onmessage = function(e) {
outsideResolve(e.data)
}
This idea uses closures to pass the resolve
function from inside the Promise callback into the parent scope, and then into the web worker event handler. Now the worker can resolve the Promise itself without needing access to the inner scope of the Promise callback.
You can wrap the entire thing inside a function and return the Promise. Now, all you need to do to communicate with a web worker is call an async function!
Here's a small (contrived) example:
// main.js
const worker = new Worker("worker.js")
let outsideResolve
worker.onmessage = function(e) {
outsideResolve(e.data)
}
function calculateSomething(n) {
return new Promise((resolve, reject) => {
worker.postMessage(n)
outsideResolve = resolve
})
}
const result = await calculateSomething(123)
Hope this helps!
22