JavaScript is a single-threaded language, which means only one script can be run at a time. Working with your UI Dom and performing complicated computations can occasionally result in issues that cause apps to run slowly or appear unresponsive.
It is common to get confused between multithreading and asynchronous programming. Since asynchronous tasks are non-blocking and can be performed concurrently, they are not dependent on one another. But they are still using single-thread.
To use Multithreading for complex calculations, here comes the concept of web workers.
Example used for this article can be found in the following link
What is a web worker?
A web worker is a JavaScript process that runs in the background,separate from the main thread of a web page. The main thread is the default JavaScript thread, which we refer to as a single thread.
This is responsible for running all the JavaScript for a web page as one line at a time. So basically, a web worker allows you to execute multiple threads of JavaScript in parallel with each other. To avoid the main thread doing all the heavy lifting itself, a web worker can be created and used to offload expensive work, so the main thread can continue executing other code. To be aware, there is one disadvantage that can be faced: that a web worker can’t be used to manipulate the DOM, only the main thread can access the DOM and manipulate it.
How and where can we use a web worker and run it parallelly with the main thread?
Now, as we know what a web worker is, we will see how and where it can be implemented and used.Here is a simple example:
We have two buttons: one for doing a sum and the other to change the background color. If we try to calculate the sum and immediately try to change the background color, it may cause a block up of the main thread. As we can see below, for loop is an expensive operation and we have only one thread that is working on the sum calculation, so it will prevent any other operations until it’s finished with the for loop.
const sumButton = document.getElementById("sumButton");
const backgroundButton = document.getElementById("backgroundButton");
sumButton.addEventListener("click", function () {
let sum = 0;
for (let index = 0; index < 10000000000000; index++) {
sum += index;
}
alert(`total sum ${sum}`);
});
backgroundButton.addEventListener("click", function () {
if (document.getElementById("container").style.backgroundColor != "blue") {
document.getElementById("container").style.backgroundColor = "blue";
} else {
document.getElementById("container").style.backgroundColor = "green";
}
});
To avoid this problem , we can create web workers that will work in parallel in a way that the web worker and the main thread will be communicating with each other to pass the data. In order to use it,we can create an instance.
We will define the constructor for web worker as following:
const worker = new Worker("worker.js");
As previously shown in the image, the worker constructor takes the path of worker script,so first, we will need to create a file where we will define the work that worker will do. Once created, we need to understand how we can pass the data to and from the main script and the worker. The way we pass or offload the data to the worker is by using the method postMessage(). Essentially, the post message raises an event from one script that other scripts can listen to. We can set up an event listener on worker script in the following way to listen for new post messages:
self.onmessage= function(message){}
Here, we are creating an event handler, so whenever we get a new post message ,the worker needs to do something.
Now in order to solve the problem we previously mentioned of executing heavy loop to calculate the sum, we will move the code to worker script:
self.onmessage = function (message) {
let sum = 0;
for (let index = 0; index < 10000000000000; index++) {
sum += index;
}
this.postMessage(sum);
};
In this way, the worker will simultaneously do all the sums in the background process to avoid blocking up the main thread. The problem here is the worker will be doing the sum, but it’s not actually telling the main thread whenever it’s done. So, for that we will use postMessage(). The worker is sending the sum to the main thread through the postMessage() and the main script will catch the message:
onmessage = function (message) {
let sum = 0;
for (let index = 0; index < 10000000000000; index++) {
sum += index;
}
this.postMessage(sum);
};
worker.onmessage = function (event) {
alert(`Total Sum: ${event.data}` );
};
Main thread script will look like this:
const worker = new Worker("worker.js");
const sumButton = document.getElementById("sumButton");
const backgroundButton = document.getElementById("backgroundButton");
sumButton.addEventListener("click", function () {
worker.postMessage("Sum Button clicked");
});
worker.onmessage = function (event) {
alert(`Total Sum: ${event.data}` );
};
backgroundButton.addEventListener("click", function () {
if (document.getElementById("container").style.backgroundColor != "blue") {
document.getElementById("container").style.backgroundColor = "blue";
} else {
document.getElementById("container").style.backgroundColor = "green";
}
});
To conclude, despite the fact that JavaScript is a single thread, we can still use web workers to run our tasks concurrently and in an efficient way without affecting the main thread.
Bibliography
Multithreading in Javascript Using Worker Threads
Multithreading Javascript
Top comments (10)
Super interesting article! Great job Arshia!
Thank you so much!!!😊
Very informative Thanks 👍
Thank you so much😊
Love it! 😍
Thank you so much 😊
Wow super informative 🌟👍
Thanks a lot.😊
Thanks, great article!
Thanks a lot😊