What is an Event Loop?

Concept:

Event Loop is an execution model in which the main thread reads execution events from the “task queue”. This process is cyclic, and this mechanism is called Event Loop.

Objective:

JavaScript is a browser/Node mechanism that allows javaScript to run in a single thread without blocking, which is the principle we often use asynchronously.

2. Why is there Event Loop?

Javascript is a single-threaded non-blocking scripting language since its birth. Single-threaded means that at any time when javascript code is executed, there is only one main thread to handle all tasks, that is, only one thing can be done at the same time. Therefore, js has event loops because JS is single-threaded.

Iii. What are the Event Loop models?

There are different implementations in different places, and browsers and NodeJS implement their own Event loops based on different technologies.

** Browsers: **Event loops are explicitly defined in the HTML5 specification.

Node-js: Event Loop is implemented based on Libuv. Refer to Node and libuv’s official documentation.

Libuv has made an implementation of Event Loop, while THE HTML5 specification only defines the model of Event Loop in browsers, and the specific implementation is left to the browser manufacturers.

Task Queue

It is a fifO data structure.

Since JS is single-threaded, the next task is not completed until the previous one is completed, and if the previous one takes a long time, the latter one has to wait forever. Thus, all tasks can be divided into two types, synchronous and asynchronous.

** Synchronous tasks: ** waits in the call stack for the main thread to be executed in sequence (tasks queued on the main thread can only be executed after the previous task is completed);

Asynchronous tasks: Tasks that do not enter the main thread but enter the Task queue will be executed only if the task queue notifies the main thread that an asynchronous task is ready to execute.

Macrotask and microtask represent two types of asynchronous tasks

** Macro task :** It can be understood that the code executed each execution stack is a macro task (including fetching an event callback from the event queue and placing it on the execution stack each time, each macro task will complete the task from beginning to end, and will not execute other tasks), including the following contents:
  • setTimeout

  • setInterval

  • SetImmediate (Exclusive to Node)

  • RequestAnimationFrame (browser only)

  • I/O

  • UI Rendering (browser only)

  • Includes the overall code script

Microtask:, which can be understood as a task executed immediately after the completion of the current task, including the following contents:

  • Process. nextTick (Node only)

  • Promise

  • Object.observe

  • MutationObserver

5. Event Loop for browser

Note:

  • Macrotask takes one task from the queue at a time to execute, and then executes the tasks in the microtask queue.
  • The current stack immediately processes all events in the microtask queue before fetching an event from the macro task queue. Microtasks are always executed before macro tasks in the same event loop.
  • If a microtask is created during the execution of a task in the microTask queue, it is added to the end of the queue and executed in this cycle until the MicroTask queue is empty and stops.

Let’s start with a simple example:

setTimeout(()=>{
    console.log("setTimeout1");
    Promise.resolve().then(data => {
        console.log(222);
    });
});
setTimeout(()=>{
    console.log("setTimeout2");
});
Promise.resolve().then(data=>{
    console.log(111);
});
Copy the code

Think about it, what is the result of the run?

The running results are as follows:

111
setTimeout1
222
setTimeout2
Copy the code

Consider the order in which the following code is executed:

console.log('script start');

setTimeout(function () {
    console.log('setTimeout---0');
}, 0);

setTimeout(function () {
    console.log('setTimeout---200');
    setTimeout(function () {
        console.log('inner-setTimeout---0');
    });
    Promise.resolve().then(function () {
        console.log('promise5');
    });
}, 200);

Promise.resolve().then(function () {
    console.log('promise1');
}).then(function () {
    console.log('promise2');
});
Promise.resolve().then(function () {
    console.log('promise3');
});
console.log('script end');
Copy the code

Think about it, what is the result of the run?

The running results are as follows:

script start
script end
promise1
promise3
promise2
setTimeout---0
setTimeout---200
promise5
inner-setTimeout---0
Copy the code

NodeJS Event Loop

In Node, the event loop behaves roughly the same as in the browser. The difference is that Node has its own model. The implementation of event loops in Node relies on the Libuv engine. As we know, Node selects Chrome V8 engine as the JS interpreter. V8 engine analyzes THE JS code and calls the corresponding Node API, which is finally driven by libuv engine to perform the corresponding tasks and put different events in different queues waiting for the main thread to execute. So the event loop in Node actually exists in the Libuv engine.

NodeJS Event Loop, which executes the macro queue callback task has 6 stages, as shown below:

From the above model, we can roughly analyze the event cycle sequence in node:

External input data –> Polling stage –> Check stage –> Close callback stage –> Timer detection stage –>I/O callback stage –> IDLE stage Prepare)–> Polling stage…

Stage function:

  • Timers: This phase performs callbacks in the timer queue such as setTimeout() and setInterval().
  • I/O Callbacks: This stage performs almost all callbacks. But not close events, timers, and setImmediate() callbacks.
  • Idle, prepare: This stage is for internal use only and can be ignored.
  • Poll: Waiting for new I/O events. Node blocks here in some special cases.
  • The check: setImmediate() callback is performed at this stage.
  • Close Callbacks: such as socket.on(‘close’,…) The callback to this close event.

NodeJS Event Loop procedure:

  • Synchronous code that executes the global Script

  • To execute microtask tasks, execute all tasks in the Next Tick Queue and then all tasks in the Other MicroTask Queue

  • The Event Loop in the browser is used to select only the first macrotask from the macrotask queue. The Event Loop in the browser is used to select the first macrotask from the macroTask queue. After the completion of macroTask in each stage, the microtask is performed.

6. Main differences between NodeJS and browser Event Loop

Browser: The microTask task queue is executed after each MacroTask execution.

Nodejs: MicroTasks are executed between phases of the event cycle, i.e. tasks in the MicroTask queue are executed after each phase is completed.