We've always talked about JavaScript as being a single-threaded interpreter, but as I've discussed in my previous post, the interpreter part isn't quite so true. So maybe the other part about being single-threaded isn't true either?
Multi-Threaded in the Browser
Turns out, we can make JavaScript multi-threaded by using WebWorkers. WebWorkers enable code to be run in the background, outside of the main thread. This can be useful to offload intensive calculations while the main thread that handles the UI remains responsive. WebWorkers can do almost all of the same operations that the main thread can do, except they can not manipulate the DOM or access properties of the global window
object as they operate in a different global context.
WebWorkers are created with const myWorkers = new Worker(‘path to worker code’);
and they use message passing to interact with the main thread. The WebWorker will send a message through the native function postMessage()
, and the main thread will handle the message through the onmessage
event handler. WebWorkers can be terminated early by calling .terminate()
. WebWorkers can be created from other WebWorker threads as well.
There are three types of WebWorkers: Dedicated Workers that can only be used by a single source, Shared Workers that can be shared among multiple sources – but each source must be from the same domain, and Service Workers that act as go-betweens for apps, browsers, network, or cache.
Multi-Threaded in the Server
Node.js can also make JavaScript multi-threaded by using worker-threads
. They are more useful for background calculations than for file I/O, as Node claims that their native asynchronous file I/O methods are faster than worker threads. To use worker threads, they must first be imported from worker-threads
, and then created withconst worker = new Worker(__filename, { workerData: script });
. Worker threads can create new Worker threads as well.
What's the catch?
Have an app that is multi-threaded sounds useful, as CPUs are now increasing multi-threaded performance at a faster rate than single-threaded performance is increasing. Multi-threaded applications can take better advantage of modern hardware, and can help make apps feel more responsive if the main thread that handles UI is never bogged down with a lengthy computation.
However, multi-threading introduces several issues. Writing multi-threaded code can be more difficult in implementation, testing, and debugging. If several threads are trying to access and change the same piece of data, one thread's results can change the results for a different thread, which is called a Race Condition. Multi-threaded code also needs more safeguards against these issues, so special code called Mutex (mutual exclusion) and Semaphores are used. Mutex will lock a piece of shared data until completion before releasing the lock, which can sometimes result in deadlock scenarios when a single thread has multiple mutex locks that can not be resolved and unlocked for other threads. Semaphores typically use signals and flags to prevent other threads from accessing that piece of data. Mutex and Semaphore code can be difficult to implement.
Looks like JavaScript can be multi-threaded. It's up to you to decide whether the benefits of concurrency and parallelism outweigh the different problems that they introduce.
Sources
Top comments (0)