If you are a web developer, you must have faced or will face a situation where you have to load considerably large data from an API or another source into your web app. Handling large data in the backend ( server-side ) is not the same as in a browser. We will have control over the hardware and architecture in the case of a backend system but we are talking about the client’s browser in the case of a website ( the HTML and js part ), for all we know people might be using the Internet Explorer as their primary browser ( yes they still exist ). Enter Web workers.
What are web workers?
Web workers are of three types,
- Shared web worker
- Dedicated web worker
- Service worker ( See my article on PWAs, which will show how service workers are used in a web application ).
For this article, we will be looking at Dedicated web workers and we will call them simply Web workers, the rest are beyond the scope of this article.
How does it work?
In this section, we will see how web workers handle js in the background.
- We can initiate a worker inside a script with the command
Note: We cannot spin off a worker inline like other programming languges ( example: java, C#, php ), rather we can only load js files. There are ways to implement it inline but, its beyond the scope of this article ( Refer this link ).
- The above command will initiate a web worker in another thread. Every variable, object, and function declared inside the worker will be in its own scope, meaning we cannot access a variable declared inside a web worker from a js file directly.
- We can only communicate with a worker using Broadcast Channel.
- To put it simply we will send a value ( string/object/number ) from a js file to a web worker or vice versa using this.postMessage(<data>).
- We can receive data from a js or web worker file with this.onmessage = (data)=> ( incase of web worker ) and worker.onmessage = (data)=> ( in case of a js file, worker object is obtained from new Worker() instance ).
- We can terminate a worker using either worker.terminate() ( In case of the main thread JS file ) or this.close() ( In the case of a Web worker ).
In this section, we will create a simple web application and implement web workers in it.
The above picture shows our application’s folder structure, we will send data from HTML to the web worker and print it.
We have a simple HTML page, with no components just displaying the text “Sample web workers”.
- In the first line of the script, we initiate a worker by a new Worker(‘src/worker.js’).
- Following line, we send data to that web worker with worker.postMessage(‘Hi this is Js’). We can also send objects and raw binary data using ArrayBuffer.
- We cannot send functions as web worker API uses a structured clone algorithm for copying objects and it doesn’t support copying functions.
That’s it, on the next section we will explore our worker.js file.
In this file, we just simply listen to the data.
this.onmessage will listen for the data from the file that initiated it ( In our case it’s the HTML file ).
If you want to send data from the worker to the js file see the below code.
here we just send the data using the same postMessage function that we used in our js file and
this.close()will terminate the web worker.
Note: It is best practice to terminate a web worker when not needed. Not doing so may lead to memory leaks
Here we listen for the message from the worker file and console it. Note that we use
this.onmessage because we are listening to the data from the worker.
We cannot open the HTML page in a browser directly, as Web workers need an origin to work. So you can either use VS code extension Live Server or serve npm package for serving the files, both are simple and easy to use.
When you run the file in the browser, you will see two console logs one from the worker, and another from our HTML file.
When you expand any one of the consoles you find a lot of information in the object, the “data” key contains the value that we sent.
As with any other feature, we have some limitations with web workers also, some of them are listed below.
- Creating web workers will span real OS-Level threads that consume system resources. So we have to plan ahead on which situations to use them.
- Web workers don’t have access to DOM, window, or document object. So if we want to display or manipulate the DOM objects based on the data from a worker, we have to get data from that particular web worker through channels.
- Web workers use a structured clone algorithm for copying objects and they are not given time to clean allocated memory. So terminating web workers abruptly may lead to memory leaks.
So when do we need web workers, below are some scenarios where we can make use of it.
- Prefetching data from API.
- Complex updation on Browser DB ( example Index DB ).
- Image filtering and rendering.
- Processing media data ( Video and Audio ).
Happy coding !!!
Github repo link: https://github.com/kishork2120/Webworkers-tutorial