How to write a Promise wrapper around Web Workers API?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Web Workers are already asynchronous, but the raw event-based API is awkward when you want a clean request-result flow. A Promise wrapper lets you treat a one-off worker job like any other async function: send input, await output, and handle errors in one place.
The Core Worker Contract
A worker communicates with the main thread through messages. The main thread posts data with postMessage, and the worker replies with its own postMessage.
A minimal worker file might look like this:
Without a wrapper, the caller has to manage onmessage, onerror, and cleanup manually every time.
A Simple Promise Wrapper
For one-shot jobs, wrap the worker in a Promise and terminate it when the result arrives.
This gives you a normal Promise-based interface while still using the worker thread underneath.
Why This Pattern Works Well
A Promise wrapper is a good fit when each worker instance does exactly one job. It simplifies these concerns:
- success handling
- failure handling
- cleanup with
terminate() - '
awaitintegration in calling code'
The caller no longer needs to remember worker lifecycle details for every use.
Add Structured Error Handling
Worker runtime errors and application-level errors are different. If your worker code can fail in a normal way, send a structured message instead of relying only on onerror.
Then unwrap it in the Promise wrapper:
That separates JavaScript execution errors from your own domain-level validation failures.
When One Worker Per Call Is Not Enough
If you need to reuse a worker for many requests, a single Promise wrapper is not enough by itself. You then need request IDs so multiple outstanding messages can be matched to the correct Promise.
That is a more advanced pattern, but the same idea holds: store a resolver and rejector for each request, and clear them when the matching response arrives.
Common Pitfalls
A common mistake is forgetting to terminate a one-shot worker. That leaves background threads alive longer than necessary.
Another mistake is assuming onerror catches every logical failure. It only catches worker script errors, not all application-level bad input. Send structured error messages when the worker can reject validly.
A third issue is posting data that cannot be cloned efficiently. Large payloads can make worker communication slower than expected, so consider transferables when moving big buffers.
Summary
- A Promise wrapper makes one-off worker usage much cleaner
- Wrap
onmessageandonerrorinside a Promise and terminate after completion - Use structured messages if the worker needs to report application-level failures
- Reused workers require request IDs, not just one Promise for the whole worker
- Watch payload size because worker messaging still has transfer costs

