What are workers in JavaScript used for?
TL;DR
Workers in JavaScript are background threads that allow you to run scripts in parallel with the main execution thread, without blocking or interfering with the user interface. Their key features include:
- Parallel processing: Workers run in a separate thread from the main thread, allowing your web page to remain responsive to user interactions while the worker performs its tasks. It's useful for moving CPU-intensive work off the main thread and be free from JavaScript's single-threaded nature.
- Communication: Uses
postMessage()
andonmessage
/'message'
event for messaging. - Access to web APIs: Workers have access to various Web APIs, including
fetch()
, IndexedDB, and Web Storage, allowing them to perform tasks like data fetching and persisting data independently. - No DOM access: Workers cannot directly manipulate the DOM, thus cannot interact with the UI, ensuring they don't accidentally interfere with the main thread's operation.
There are three main types of workers in JavaScript:
- Web workers / Dedicated workers
- Run scripts in background threads, separate from the main UI thread.
- Useful for CPU-intensive tasks like data processing, calculations, etc.
- Cannot directly access or manipulate the DOM.
- Service workers
- Act as network proxies, handling requests between the app and network.
- Enable offline functionality, caching, and push notifications.
- Runs independently of the web page, even when it's closed.
- Shared workers
- Can be shared by multiple scripts running in different windows or frames, as long as they're in the same domain.
- Scripts communicate with the shared worker by sending and receiving messages.
- Useful for coordinating tasks across different parts of a web page.
Workers in JavaScript
Workers in JavaScript are a way to run scripts in background threads, separate from the main execution thread of a web page. This allows for long-running or computationally intensive tasks to be offloaded from the main thread, preventing the user interface from becoming unresponsive or janky.
Web workers / Dedicated workers
- Run scripts in background threads separate from the main UI thread.
- Designed for CPU-intensive tasks like data processing, mathematical computations, etc. Generally the non-async work.
- Cannot directly access the DOM or other main thread resources for security.
- Communicates with main thread via asynchronous message passing –
postMessage()
andonmessage
/'message'
. - Terminated when main script is unloaded or explicitly terminated.
Web workers can be used for:
- Image/video processing
- Data compression
- Complex math
Creating a web worker
To create a web worker, you need a separate JavaScript file that contains the code for the worker. Here's an example:
main.js
(main script)
// Check if the browser supports workersif (window.Worker) {// Create a new Workerconst myWorker = new Worker('worker.js');// Post a message to the workermyWorker.postMessage('Hello, Worker!');// Listen for messages from the workermyWorker.onmessage = function (event) {console.log('Message from Worker:', event.data);};// Error handlingmyWorker.onerror = function (error) {console.error('Error from Worker:', error);};}
worker.js
(worker script)
// Listen for messages from the main scriptonmessage = function (event) {console.log('Message from Main Script:', event.data);// Perform a task (e.g., some computation)const result = event.data + ' - Processed by Worker';// Post the result back to the main scriptpostMessage(result);};
In this example:
main.js
creates a worker using theWorker
constructor and specifiesworker.js
as the script to run in the worker thread.- It posts a message to the worker using
postMessage()
. - The worker script (
worker.js
) listens for messages from the main script usingonmessage
. - After processing the message, the worker posts a message back to the main script using
postMessage()
. - The main script listens for messages from the worker using
onmessage
on theWorker
instance.
Service workers
- Act as a network proxy between web app, browser, and network.
- Can intercept and handle network requests, cache resources.
- Enable offline functionality and push notifications.
- Have a lifecycle managed by the browser (install, activate, update).
- No access to DOM and main thread resources for security.
Service workers can be used for:
- Caching
- Offline support
- Request handling
- Background sync
Creating a service worker
main.js
(main script)
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/service-worker.js').then(function (registration) {console.log('Service Worker registered:', registration);}).catch(function (err) {console.log('Service Worker registration failed:', err);});}
service-worker.js
(service worker script)
self.addEventListener('fetch', function (event) {event.respondWith(caches.match(event.request).then(function (response) {// return cached response if availableif (response) {return response;}// Otherwise, fetch from networkreturn fetch(event.request);}),);});
In this example:
- The main script registers a service worker at
/service-worker.js
. - The service worker listens for the
fetch()
event, which is fired whenever the browser makes a network request. - The service worker first checks if the requested resource is cached using
caches.match(event.request)
. - If it is, it returns the cached response. Otherwise, it fetches the resource from the network using
fetch(event.request)
.
Shared workers
- Can be accessed from multiple scripts in different windows/tabs/iframes.
- Allow data sharing between browser contexts via a messaging interface.
- Similar to dedicated web workers but with a broader scope.
Use cases for shared workers:
- State sharing across multiple windows.
Bonus: Worklets
The Worklet
interface is a lightweight version of Web Workers and gives developers access to low-level parts of the rendering pipeline. With Worklets, you can run JavaScript and WebAssembly code to do graphics rendering or audio processing where high performance is required.
You are not expected to know about worklets, so it won't be covered in great detail. Read more about worklets on MDN.
Considerations and limitations
- Same-Origin policy: Workers must comply with the same-origin policy, meaning the script that creates the worker and the worker script itself must be from the same origin.
- No DOM access: Workers do not have direct access to the DOM. They can communicate with the main thread through messages.
- Performance: Creating and managing workers incurs overhead. They should be used judiciously for tasks that truly benefit from parallel execution.
- Error handling: Proper error handling mechanisms should be in place to handle any issues within the worker scripts.