How to Perform Multithreading in JavaScript?
Javascript is a single-threaded language, meaning that just one line of code may be run at once. Javascript is single-threaded because, originally, it was only a web browser scripting language created to serve the needs of a single user on a single window of the browser, eliminating the need for multithreading. Additionally, the asynchronous programming capabilities provided by Javascript through the event loop were a perfect method to get around the blocking behaviour and operate as smoothly as a multi-threaded application.
However, now that it has evolved into something much bigger and just taken over the web, there are scenarios where huge computations are also performed by Javascript, and browsers may execute complicated algorithms or produce intricate visualisations. These time-consuming procedures ultimately cause the thread to become blocked, slowing down UI events and triggers. Still, it is not feasible to change the language in such a fundamental way. Adding concurrency would require a redesign of the language. It cannot just be tacked on.
If you want multi-threading, it means that you probably want to process a computationally long task. The best option in a particular situation would be to relocate certain processing from an application to the server side, where it will have access to additional processing power and a true threaded execution environment (a web server).
However, there may come a situation when that is just not an option and JavaScript must either be able to do something or be damned. Multi-threading is the only solution left in this situation. But there is nothing a JavaScript coder can do to change the fact that JavaScript doesn't actually support multithreading. We may, however, imitate multithreading to the extent that it results in one of the advantages of a multi-threaded environment: the ability to execute extremely demanding programmes. This is what our subject of today's discussion is: Javascript Multithreading
Javascript developed a hot new technology in 2009 called "Web Workers" to enable this simulation and address this issue. Web workers allow us to write multi-threaded Javascript that doesn't block the DOM. To some extent, even asynchronous operations block the DOM. Web Workers are an essential part of Javascript Multithreading.
What are Web Workers in JS?
Web Workers are JS scripts that are run in a background thread separate from the main execution thread from an HTML page. Messages are used to transfer data between the main thread and the workers. You may use web workers to conduct process-intensive operations from the browser without creating blocked instances since they operate on a different thread from the main execution thread.
Web workers are provided as functionality by the browsers to enable Javascript Multithreading. In actuality, they are the Operating System threads that may be launched in the background of your current page to allow it to carry out labour-intensive and complicated activities.
Why Use JavaScript Web Workers?
Web workers enable you to create background execution threads that are independent of the main execution thread, which is often used to perform the user interface's logic.
The fundamental advantage of this division and isolation of tasks is that you may conduct expensive activities in a separate thread without interfering with or negatively affecting the responsiveness and usability of the main thread. When the background thread’s task is done, it informs the main thread of the results smoothly through Javascript’s event handling.
Consider the scenario when you wish to do intricate computations in response to a button click. If you start doing the job right away, you’ll tie everything up. The user won't be able to scroll or click anything on the website. The dreaded "this website is unresponsive" error message could even appear for them. In this case, web workers would enable you to operate quietly in the background while the user of your page continues to do so undisturbed in the foreground. Technically, we say the background work takes place on another thread. This is how javascript multithreading would be enabled.
Therefore, you could allow the user to input data into the browser, pass those variables to the worker, and then let it perform the computation in the background while you allow the user to perform other tasks in the main thread. When the worker is finished, it will pass the result back and you can then print it to the page. You may even work on several issues simultaneously and pass back the solutions out of order as they are resolved.
So, if web workers allow the non-DOM to be executed on separate threads, a question might have encountered you:
Isn’t Javascript Allowing True Multithreading using Web Workers, Rather Than the ‘Simulation of Multi-threading’ That We Stated Earlier?
Javascript is still single-threaded, even with web workers. V8 (the javascript engine) allows a single thread per JS Context, and this means it is simply not possible to create a new thread. However, we still are able to spawn new ‘workers’ who are just working on the other threads. For this to be answered, consider a question, Is it possible to perhaps create two V8 processes and have them both interpret some JS code? This is the solution to this issue. Messages are used by workers to communicate since their contexts are diverse. Workers are unfamiliar with our setting or context, and they require some information in the form of a message.
Concurrent access to shared variables, which is a headache in multithreading systems, is not a concern with JavaScript. Every developer writes code as though each access to a variable is consistent without ever considering the issue. Or in a way, there is no need to be concerned about the so-called Memory model. The reason is again because the contexts are different. There is no need to think of Web Workers in terms of parallel processing while writing the code.
How do We Exchange Data With a Worker?
Data transfer between the main thread and the workers happens via a system of messages; messages are sent using the postMessage() function and received using the onmessage event handler (the message is stored in the message event's data parameter). Instead of being shared, the data passed between the main thread and the workers are duplicated. When considering memory allocation and data transmission speed, we should keep this in mind. The following snippet of pseudo-code illustrates the above explanation: In the file containing the code for the main thread,
This is how we create our worker. Next,
(Here a web worker has been created with the name myWorker) In the file containing the code for the worker1 thread,
Note: instead of onmessage, we can also simply use addEventListener callback.
In this process of data exchange, the algorithm called Structured Clone Algorithm has to be called to clone that object. This algorithm simply recurses through the object and creates a clone of it.
Setting Up Web Workers & Multi-threading to JavaScript
In this section, we discuss how we set up and use Web Workers in order to take advantage of multi-threading in Javascript.
A.js file is launched as a "worker" and executes commands on a separate thread. It and the "main" thread can exchange data back and forth. However, certain things, like the DOM, are off limits to workers.
Let’s go through a use case to understand it better. A group of friends is supposed to stay at a resort. Some of them are already members of the resort and hence they get a direct entry without the tedious registration process. On the other hand, the non-registered members have to go through this process first.
The issue here will be that if a person has to register, he/she and all other people after him/her have to wait. This is called the ‘blocking’ behaviour. However, javascript has an elegant way to deal with blocking by handling asynchronous calls. But what if this registration process is so complex that it causes even async calls to block the execution? Here we can use Web Workers. The following code shows how we use Web Workers to solve this problem:
Creating a Project Folder and Adding index.html in the Root of It
This file displays the list of people who get the entry to the resort.
Adding Javascripts Files, Separately for the Main Thread and The Worker Thread
main.js
worker.js
Output:
Explanation
- In the code, we first check if the person is already a member of the resort or not. If yes, they are given the entry and appended in the entry list. However, if they are not, they have to undergo the process of registration.
- Because this process takes time and we don’t want the further people to get blocked and wait for it, we assign another person for the task of registration. This is illustrated in the code by creating a new worker.
- The data of the person is passed on to the worker, and the main thread execution continues with other members. This is why you may encounter that the names of non-members are after some of the members just after them, because they didn’t have to wait.
- We are utilising a long while loop to handle some processing in order to imitate the registration procedure. This may actually be some CPU-intensive cryptographic code, picture processing, or anything else that would obstruct the main thread and render the page unusable.
- Once registered, the worker thread notifies the main thread by delivering data. The main thread then uses the event listener to monitor the data and notifies the user, adding it to the DOM.
- The worker thread uses close() to indicate that the task for which it was created, has been accomplished and it is no longer required
Make your code speak volumes. Enroll in our JavaScript online course and learn how to craft impactful, functional web applications.
Frequently Asked Questions:
Can a Worker Thread Access the DOM or the Windows Object?
Ans: No, Javascript runs a single execution context on a single thread. DOM and UI is handled by the main thread, and hence the worker thread has a separate context. As a result, the worker thread does not have access to the window or document objects, but it may use some of the window object's features, such as Websockets and indexedDB.
Why is the Worker Supposed to be Present in a Separate File?
Ans: It is just another consequence of ‘separation of contexts’. The worker code must be in a different file, which we can use to establish a separate worker thread by giving the location of the file to the Worker function.
Note: In the example described above, we can also add a button to the UI, and it can be observed that if web workers are not used and the registration process is carried out everytime there is a non-member, that button will not work. The reason is the main thread is blocked and busy in carrying out the registration process. However, the button works when web workers are used.
Conclusion
In this article, we discussed:
- Why Javascript is single-threaded: It is a web-based UI language and didn’t require complexities of multi-threading
- Why multithreading is needed in Javascript: Now given the scope of JS in the industry, many complex codes may be needed to run in Javascript
- How is multithreading achieved in Javascript: through Web Workers
- Web Workers don’t really make Javascript ‘multithreaded’. It is just a simulation of multi-threading, and web workers allow different threads with different contexts and call stacks to run parallely and communicate with each other.
- How do we exchange data between the threads: through postMessage() and onmessage or event handlers
- A example to see how web workers work