DEV Community

Cover image for JavaScript's Secret Sauce: How Single-Threaded Becomes Asynchronous
tanishparashar
tanishparashar

Posted on • Updated on

JavaScript's Secret Sauce: How Single-Threaded Becomes Asynchronous

JavaScript is single-threaded, so how does it manage asynchronous operations? The answer is simple: it doesn't—at least not directly.

JavaScript delegates these tasks to the browser or Node.js runtime, which is more than just the V8 engine executing JavaScript code.

Here's what really happens behind the scenes:

Web APIs

  • These are provided by the browser (or Node environment) to handle asynchronous tasks. Examples include setTimeout, XMLHttpRequest, and DOM events.

Callback Queue

  • Once an asynchronous operation (like a timeout or an AJAX request) is completed, its associated callback is placed into a callback queue.

Event Loop

  • The event loop is constantly checking the call stack (where JavaScript code executes). If the stack is empty, the event loop picks the next callback from the callback queue and pushes it onto the stack for execution.

Let’s look at a piece of code that demonstrates how the event loop manages asynchronous operations:

$.on('button', 'click', function onClick() {
    setTimeout(function timer() {
        console.log('You clicked the button!');    
    }, 2000);
});

console.log("Hi!");

setTimeout(function timeout() {
    console.log("Click the button!");
}, 5000);

console.log("Welcome to loupe.");

Enter fullscreen mode Exit fullscreen mode

Remember, JavaScript doesn't wait for setTimeout or other async functions to finish before moving on. It delegates those tasks, and once they're done, the callback is added to the queue.

Hi!
Welcome to loupe.
Click the button!
You clicked the button!

Enter fullscreen mode Exit fullscreen mode

What Happens Here?

Synchronous Tasks: When JavaScript runs, the call stack executes the tasks in order. First, it logs "Hi!", then "Welcome to loupe." because these are synchronous operations.

Asynchronous Tasks: The setTimeout function creates timers. But instead of blocking execution, these tasks are handed off to the browser’s Web APIs to wait for 2000ms and 5000ms, respectively.

Callback Execution: Once the specified time elapses, the callbacks (console.log("You clicked the button!") and console.log("Click the button!")) are moved into the callback queue. The event loop checks if the call stack is empty and then pushes these callbacks back onto the stack to be executed.

Image description

Visualizing the Call Stack

  • JavaScript’s call stack is LIFO (Last In, First Out). Only one task is processed at a time. If there's a long-running task (like a loop), it blocks the stack, which is why asynchronous callbacks like setTimeout help avoid blocking, allowing smoother execution.

The Importance of Asynchronous Callbacks

  • Understanding JavaScript’s event loop, call stack, and Web APIs is crucial because it gives insight into how asynchronous operations are handled, enhancing the efficiency and responsiveness of web applications.

In JavaScript, asynchronous callbacks are not optional. They're necessary to avoid blocking the main thread, especially for tasks like AJAX requests or setTimeout. This ensures your app runs smoothly, with no interruptions to the user experience.

To truly master JavaScript's asynchronous behavior, understanding the event loop is key. Be sure to check out this video and visualize the process with Loupe.

Top comments (5)

Collapse
 
suhani_acharya profile image
Suhani Acharya • Edited

I hope you post more and gain more attention. Nobody really talks about these things and you've covered it properly 🔥

Collapse
 
tanishparashar profile image
tanishparashar

ThankYou 😊

Collapse
 
tanishparashar profile image
tanishparashar

Hey @gunika1321 it would be really helpful if you could list some of them for me

Collapse
 
darcher profile image
Dylan Archer • Edited

Great early posts, read through your post here too: dev.to/tanishparashar/how-js-works...

Before they were "all the rage" web workers were my go-to approach for segmenting and isolating heavy operations inside of their own thread. Now we also have Service workers, made popular when Progressive Web Apps went mainstream, that help in areas like intercepting network calls or providing or storing data for offline use inside of their own thread. That may be a nice topic for your next article.

Great work!

Collapse
 
gunika1321 profile image
gunika1321

Excellent explanation. Could you please post more about these small neglected yet useful topics related to JS?