All You Need To Know About Event Loop (2)

Event Loop

while (queue.waitForMessage()) {
	queue.processNextMessage();
}

Let’s check the code above.
Assuming the ‘waitForMessage’ function behaves synchronously. It means it runs an infinite loop and waits for a message, and if there is a message, process the next one.

In other words, the Event Loop is not a component of the JavaScript engine, but manages which job to pile up on the call stack in the running environment (Browser or runtime environment such as Node.js).

Here is a brief explanation of how the event loop works.

  1. If there is a job to be processed, the oldest job is executed.
  2. If there is no job to process, wait for the next job.
  3. If there is something you need to process again, go back to step 1 and repeat.

event loop

setTimeout creates a timer event, waits for the amount from the parameter of the time passed, and fires it. If there are no arguments, it returns a default value, 0. It should run immediately because the timer is set to zero, but it’s not.

Take a look at how the code flows one by one and see why.
Promise is the API mainly applied for future completion or failure situations with asynchronous operations.

In the code above, it returns the Promise through the resolve method and it passes the callback through the then method.

This code works in the following order.

  1. Call setTimeout.
  2. Put a callback in the task queue.
  3. Call Promise.
  4. The result passed from then as a callback is placed in the Micro task queue.

Micro Task

Let’s take a quick look at ‘Microtask’ here.
In ES2015, API such as Promise has been added for handling concurrency. It handles Micro tasks, slightly different from regular tasks.

Tasks are jobs that should be executed sequentially in a browser or other operating environment.

The task is simply to execute a script or callback caused by the occurrence such as setTimeout and UI event.

Micro tasks are asynchronous tasks that must be executed immediately after the currently running task. In other words, microtasks have a higher priority than regular tasks. It includes Observer API, process.nextTick in NodeJS and Promise, used in the example.

If the Microtask concept is included in the sequence of the event loop described above, code flow is like this.

  1. First check if there are microtasks, and if so, run all microtasks first.
  2. If there is a job to be processed, the oldest job is executed.
  3. If there is no job to process, wait for the next job.
  4. If there is a job, go back to step 1 and repeat.
  5. Before waiting for a task, first check if there is a microtask, run all the Microtasks first, then handling the regular task.

Returning to the example code, finally, understand what the event loop is doing.
The callback passed from the then method of Promise is a microtask, executed after entering the call-stack into by event loop. After that, it prints out hello.


microtasks

So, can solve all the problems by utilizing the asynchronous web API with your understanding of the event loop? unfortunately not.

However, the possibility still remains that the execution of the next task will be blocked by the predecessor task.
In the example below, the code is executed one after the other. At first, the ‘someExpensive’ function, an expensive operation, is pushed onto the call stack. Because of this, printing ‘hello’ is blocked from the event loop. It can only be run after the job is complete.


blocktask

In summary, tasks are always executed sequentially through the event loop, other tasks cannot run until certain tasks are completed. Microtasks queues have higher priority than regular task queues. UI events cannot be fired until all microtask queues are empty.

This means that events directly connected to the UI such as clicks, text input, and rendering can be blocked when tasks or microtasks that involve costly calculations run on the CPU. This can be a core issue to lower the user experience.

Conclusion

JavaScript Async Process

  • Network requests executed synchronously in JavaScript block the call stack, therefore the browser is impossible to run other tasks at the same time. To overcome this, apply the asynchronous callbacks as a solution
  • The asynchronous processing of the SetTimeout() function is disappearing from the call stack in javascript first, then re-piles on the stack when the call stack is empty. This process is concurrency with the Event Loop.
  • JavaScript processes only one at a time. However, browsers provide WepAPIs (DOM, Ajax, SetTimeout) to effectively support threads that can be called from javascript.
  • SetTimeout function is a separate API that does not exist in JavaScript or in the browser’s V8 engine source. It is in JavaScript’s runtime environment.
    The delay time of SetTimeout is minimal time and can be more.

Event Loop


eventloop diagram

  • The role of the Event loop is to watch the call stack and task queue, and the first callback in the queue is piled on the stack when the stack is empty.
  • Request of Fetch API is a similar processing method just like the Event loop (to process the stack after requesting and waiting outside the stack until stack is empty)
  • Likewise, addEventListener is a structure that sent from the Web API to the callback queue if an event occurs. It is sequentially stacked on the call stack then executed.

Call Stack & Rendering

  • Rendering is impossible if the call stack is full.
  • Rendering is processed as just like a callback function. It has to wait for the stack to be emptied and has a higher priority than regular callbacks. However, while the call stack is in a synchronous loop, rendering is also blocked, so other operations (e.g. selecting text on the browser screen) are impossible.
  • It is queued through an asynchronous loop and handled in a way that gives the rendering an opportunity to intervene.