August 7, 2023

Multi-threaded JavaScript with the Event Loop: Breaking the Single-threaded Barrier

The best time to establish protocols with your clients is when you onboard them.

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

What is an event loop in JavaScript ?

An event loop is a mechanism used in JavaScript to handle asynchronous code. It is responsible for managing the order in which tasks are executed and ensuring that no tasks are blocked by other tasks that are taking longer to execute.

The event loop works by continuously monitoring the call stack, which is a data structure that records the execution context of a program. When a function is called, its execution context is added to the top of the call stack. When the function returns, its execution context is removed from the call stack.

If a function is asynchronous, such as a network request or a timer, it is not executed immediately. Instead, it is added to a queue of tasks that are waiting to be executed. The event loop constantly checks this queue for tasks that are ready to be executed. When a task is found, its execution context is added to the call stack and executed.

In summary, the event loop is a key feature of JavaScript that enables the language to handle asynchronous code efficiently. It works by constantly monitoring the call stack and a queue of tasks, ensuring that all tasks are executed in the correct order without blocking the program.

When we run greetTwoPeople(), here’s what happens:

  1. The first function to be called is greetTwoPeople(). This function then calls the greet() function twice, once with the argument “Alice” and once with the argument “Bob”.
  2. When greet(“Alice”) is called, a new frame is added to the call stack for the greet() function with the argument “Alice”. The console.log() statement in greet() is executed, printing “Hello, Alice!” to the console.
  3. When the greet(“Alice”) function call completes, its frame is removed from the call stack.
  4. The greet(“Bob”) function call then adds a new frame to the call stack for the greet() function with the argument “Bob”. The console.log() statement in greet() is executed again, printing “Hello, Bob!” to the console.
  5. When the greet(“Bob”) function call completes, its frame is removed from the call stack.

Finally, when all function calls have completed, the greetTwoPeople() frame is removed from the call stack.

So the final output of this code would be:

This call stack is one of the reasons for slowness. If there is a network call or image processing in the call stack which might take time, it will stop the next processes from executing even if they are small and quick to run.
Let us understand how JavaScript can handle this:

How are callbacks and task-queue connected in the event loop?

                                     

Explanation:

  • The JavaScript application is the main program that is executed.
  • The Event Loop is responsible for managing the execution of asynchronous code and handling events.
  • Callbacks are functions that are registered to be called later when an asynchronous operation completes.
  • The Task Queue is a queue of tasks (callbacks) that are ready to be executed by the Event Loop.
  • Asynchronous operations are executed by the browser or Node.js, and when they complete, their callbacks are added to the Task Queue.
  • The Event Loop checks the Task Queue for any pending tasks, and if there are any, it executes them in the order they were added.
  • Asynchronous operations can also trigger events, which are added to the Event Queue. The Event Loop will handle these events in a similar way to tasks, by adding their callbacks to the Task Queue when they are ready to be executed.

How does all of this work?

Event loop and task queue working

  • The flow chart shows the main components of the event loop, including the event loop itself, the task queue, and the call stack. The event loop continuously checks for events and tasks, and executes them as they become available.
  • The flow chart also shows two types of tasks: callbacks and microtasks. Callbacks are functions that are queued up to be executed when an event occurs, while microtasks are functions that are queued up to be executed when the call stack is empty.
  • The call stack represents the sequence of functions that are currently being executed. When a new task is added to the queue, it is added to the end of the queue and will be executed after all the functions in the call stack have been executed.
  • When a new task is added to the queue, it is added to the end of the queue and will be executed after all the functions in the call stack have been executed. When the event loop finds a task in the queue, it moves the task from the task queue to the call stack, and the task is executed. Once the task is complete, it is removed from the call stack and the event loop continues to check for new events and tasks.

Here is an example of how it all works with javascript code:

In this code, we first log “Start” to the console. Then, we set a timeout with a callback function that logs “Callback” to the console after 0 milliseconds. Next, we create a promise that logs “Promise” to the console when it is resolved. Finally, we log “End” to the console.

Here’s how the event loop, call stack, callback queue, and task queue work together to execute this code:

  • The code is initially executed, and “Start” is logged to the console. This is added to the call stack.
  • setTimeout is called, which schedules a task to run the callback function after 0 milliseconds. This task is added to the task queue.
  • Promise.resolve().then() is called, which schedules a microtask to run the callback function when the promise is resolved. This microtask is added to the microtask queue (also called the job queue).
  • “End” is logged to the console. This is added to the call stack.
  • Since the call stack is empty, the event loop checks if there are any tasks in the task queue or microtasks in the microtask queue. If there are, it adds them to the call stack.
  • The microtask queue is processed first, since it has higher priority than the task queue. The callback function for the promise is added to the call stack, and “Promise” is logged to the console.
  • The call stack is now empty, so the event loop checks the task queue. The callback function for setTimeout is added to the call stack, and “Callback” is logged to the console.
  • The call stack is now empty, so the event loop checks if there are any more tasks in the task queue or microtasks in the microtask queue. Since there are none, the event loop waits for new tasks or microtasks to be added.

So, the output of this code will be:

As you can see, the event loop, call stack, callback queue, and task queue all work together to ensure that asynchronous tasks are executed in the correct order and at the appropriate time. The call stack is used to execute synchronous code, while the callback queue and task queue are used to schedule and execute asynchronous tasks. The event loop manages the interaction between the call stack and the task and callback queues, ensuring that tasks and microtasks are executed in the correct order and at the appropriate time.

Here is an interesting app create by Philip Roberts where you can visualize all of these processes: click here

CodeStax.Ai
Profile
August 17, 2023
-
6
min read
Subscribe to our newsletter
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Share this article:

More articles