DEV Community

Cover image for A Beginner's Guide to JavaScript's Single Thread and Event Loop
Fernanda Kipper
Fernanda Kipper

Posted on

A Beginner's Guide to JavaScript's Single Thread and Event Loop

As a Single Thread non-blocking language, JavaScript can be a bit tricky to understand at first.
When I first began exploring the language, I found myself overwhelmed with questions about how it worked. In this article, I'll try to answer some of the most common questions I had when I first started learning about the JavaScript event loop. By the end of this article, you'll have a better grasp of how JavaScript manages to remain non-blocking despite being single-threaded, and you'll be better equipped to build efficient and responsive applications using this powerful language.

Single Thread

JavaScript is a single-threaded language, which means that it has only one thread of execution. This means that all operations are executed sequentially, one after the other, in a single call stack.

The call stack is a data structure used by JavaScript to manage function invocations. It keeps track of the current position in the execution context (the point where the code is currently being executed) and all pending function calls that have been made but not yet completed.

Whenever a function is called, a new frame is added to the top of the call stack, representing the execution context of that function. When a function completes, its frame is removed from the top of the call stack and control is returned to the previous function in the stack. This allows JavaScript to maintain the order of function calls and ensure that each function completes before the next one is executed.

Look at the following example of how the Call Stack works

Image description

Image description

Non-blocking

Non-blocking code is code that allows other code to execute while it is running. Specifically, asynchronous code, that should not block the execution of synchronous code that does not depend on it.

Asynchronous code should execute in the background, without interrupting the flow of the main program. Instead of waiting for an operation to complete before moving on to the next line of code, asynchronous code should allow the program to continue executing while the operation runs in the background.

Now, you should be thinking, how does JavaScript manages to be non-blocking since executes only in one thread?

Event loop

Event Loop is the mechanism used to JavaScript to handle asyncronous code.
When an asynchronous operation is started, it is added to the callback queue and removed from from call stack. The event loop constantly checks this queue for pending tasks waiting to be executed. If there are any pending tasks, the event loop will retrieve the next task and add it to the call stack for execution. Once the task is complete, its callback function is added to the callback queue. The event loop will continue to check the callback queue for pending tasks and add them to the call stack as necessary. This process allows JavaScript to execute asynchronous code in a non-blocking way, ensuring that the main program can continue to run while waiting for long-running tasks to complete.

Consider the following code:

Image description

What would happen in the Call Stack and Callback Queue would be:

1 - First the fetchData() function would be added to the Call Stack
2 - fetch() is added to the Call Stack and initiates a network request. The Promise created by fetch()is added to the queue.
3- console.log("hello") is added to the Call Stack.

Image description

4 - After that, console.log("hello") would be executed and removed of the Call Stack
5 - fetchData() is finished executing and is removed from the Call Stack
6 - The Promise created by fetch() is resolved with the response data and the then() method attached to the Promise is added to the queue.

Image description

Image description

7 - Event Loop would takes console.log(data) and adds to Call Stack
8- console.log(data) would be executed
9 - There are no more tasks to execute, and the program terminates.

Image description

Ok, that makes sense, but now you probably asking yourself, how does the fetch gets executeded?

Browser APIs

Browser APIs (Application Programming Interfaces) are interfaces provided by the browser or the host environment that allow us to perform various operations, such as making network requests, setting timeouts, and manipulating the DOM.

These APIs are used to handle asynchronous operations in JavaScript by offloading them to the browser or the host environment, which can perform the operation in the background without blocking the main program.

So, when a fetch request is made using the fetch() method , the browser's web API (Fetch API) handles the request, sending it to the server and waiting for a response. During this time, the JavaScript program can continue to execute, thanks to the event loop, which checks the callback queue for any pending tasks. Once the server responds with the requested data, the web API adds the response to the callback queue, triggering the callback function associated with the original fetch() request.

Interesting, isn't it?


Overall, understanding the principles behind the event loop, non-blocking code, and web APIs has been essential in my growth as a JavaScript developer, and I hope this article have helped you to get a better understing of these concepts.

This kind of knowledge can be a key piece for you to take your programming skills to another level.

Thats all :)

Top comments (1)

Collapse
 
tiagosatur profile image
Tiago Satur

Great article!