Welcome folks today in this blog post we will be implementing the concept of worker threads
in javascript to implement concurrency
and parallelism
in browser using postmessage api . All the full source code of the example is shown below.
What is Worker Threads ?
Before going to the example you need to understand what the heck worker threads are in javascript. As you all know guys javascript is a single threaded language and at a time only one instruction can be executed in javascript. To tackle this problem the concept of worker threads are introduced. Because in the browser we have the DOM which is also knows as Document object model where it contains all the buttons,input fields that you interact with. All this DOM related stuff is controlled by a single thread which is called the MAIN THREAD which controls the UI of the application. So basically if you are performing some kind of background operation which is very resource intensive or requires a lot of resources or time. Then we can shift that operation to the worker threads so that they can do the work in the background. Once completed they can return the result to the main thread to update the DOM.
Advantages of Worker Threads
They are very easy to create and write
It reduces the load from the Main UI Thread
It makes the Application to load fast
Disadvantages of Worker Threads
They increase the complexity and size of application
They cannot directly update the DOM. It needs to pass the data to the Main Thread to Update DOM.
Simple Worker Threads Example
Not Using Worker Threads
First of all guys we will be seeing the situation when we execute the code without using worker threads. Create an index.html
file inside the root directory and copy paste the following code.
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Web Workers Simple Example in Javascript</title> </head> <body> <h1>Web Workers Example Using PostMessage API</h1> <button id="background">Change Background</button> <button id="sum"> Calculate Sum </button> <div id="result"></div> </body> <script src="script.js"></script> </html> |
As you can see guys in the above code we will be having two buttons performing two things. First button is responsible to change the background color of the body and it will be directly communicating with the DOM. And the second button to calculate the sum of numbers this operation will be resource intensive and here we will be calculating the sum of very large numbers using the for loop. Now if you open the index.html
file inside the browser it will look something like this
And now we need to write the javascript code for this very first example when we not use the worker threads
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
let background = document.getElementById("background"); let result = document.getElementById("result"); background.addEventListener("click", (e) => { document.body.style.backgroundColor = `#${Math.floor( Math.random() * 16777215 ).toString(16)}`; }); document.getElementById("sum").addEventListener("click", (e) => { let sum = 0; for (let i = 0; i < 10000000000; i++) { sum = sum + i; } document.getElementById('sum').innerHTML = `The sum of numbers is ${sum}` }); |
As you can see we are getting the references of both of the buttons using their id and then we are first of all binding the onclick listener to the change background button. So user when clicks on this button the body background color will change to random color. As soon as he presses the calculate sum button then automatically everything will be freezed and then main thread will not work because it will be busy in this expensive operation of calculating the sum of 1 Billion numbers. Here we are using the for loop. For 10 seconds your screen will be freezed and you can’t peform or interact with your application. So this is a really serious bug that occured inside the app. We need to find a way to counter this. In this scenario the concept of worker threads comes to the picture.
How to Create Worker Threads
Now for creating the worker threads it’s very simple just inside the root directory create a worker.js
file and copy paste the following code
And now in this file copy paste the following code
worker.js
1 2 3 |
self.onmessage = function (message) { // worker thread code here }; |
As you can see for every worker thread file we have the global variable which is called self
which is similar to window variable for the javascript
file. And inside this worker variable we have the event
that we are listening which is onmessage
which simply means whenever the main ui thread sends some message or data to the worker thread this function will automatically call itself and in the argument the data will be received which is sent by the main thread and then here we can write the code for the worker thread.
Include Worker Threads in Javascript
Now to use the above created worker threads file we new need to include this in the script.js
file as shown below
1 |
const worker = new Worker("worker.js") |
As you can see we are creating the new object of the Worker class which is in built to every browser and we are passing the path of the worker thread file which we have created.
Sending Data From Main UI Thread to Worker Thread
Now guys we will be sending some data to the worker thread from the main thread. For this you need to replace the code inside the sum
button event listener. We will be passing the below data as shown below
1 2 3 |
document.getElementById("sum").addEventListener("click", (e) => { worker.postMessage("Hello world from Main UI Thread") }); |
As you can see guys we are using the postMessage()
which is available to the main thread to communicate or Post messages or data to the worker thread. Now we will be receiving this data at the worker thread side.
Receiving Data From Main Thread in Worker Thread
Now to receive this data we have already the argument there which is message in the onmessage event handler. We need to print the data property of this message object.
1 2 3 4 5 6 |
self.onmessage = function (message) { console.log(message) console.log(message.data) }; |
So if you open the browser and inspect console you will see the data printed out
Now for our example we need to pass the 1 Billion as an argument in the postMessage() method in the script.js
file so copy paste the below code
1 2 3 |
document.getElementById("sum").addEventListener("click", (e) => { worker.postMessage("10000000000") }); |
Notice that we are passing the number inside the double quotes. It is mandatory you must pass your data inside the double quotes. Because all the things are string in javascript.
Now we need to convert the string to the number using the parseInt()
method available in javascript as shown below
1 2 3 4 5 6 7 8 9 10 |
self.onmessage = function (message) { let length = parseInt(message.data) let sum = 0; for (let i = 0; i < length; i++) { sum = sum + i; } console.log(sum) self.postMessage(sum) }; |
As you can see guys we are processing the calculation
of sum in the for loop. And lastly we are returning the result back to the main thread using the postMessage()
and in the argument we are passing the calculated sum.
Receiving the Data in Main Thread From Worker Thread
Now lastly guys we will be receiving the data which is passed by the worker thread in main ui thread in the same manner that we did earlier. Once again we will be using the same event which is onmessage
now it is invoked on the worker object. And in the callback function we got the message
which is sent by the worker thread in this case it is the sum of all the numbers. And here we are just updating the DOM and printing the sum as the label of the button.
1 2 3 4 |
worker.onmessage = function(message){ console.log(message) document.getElementById('sum').innerHTML = `The Sum of the Value is ${message.data}` } |
Now if you open the index.html
file you will see all the things will run smoothly and you will be able to perform and interact with the DOM when you press the sum button. It will take some time but in the mean time your main ui thread will be free for other DOM related actions. And once the worker threads is complete in processing or calculating the sum it will reflect back in the DOM as shown below