1. What is an Event loop
Event Loops are used to coordinate events, user interaction, scripting, rendering, networking, and rendering. A mechanism resulting from the work of the User Agent.
2. The running mechanism of JavaScript
2.1 Single-threaded JavaScript
One of the characteristics of the JavaScript language is that it is single threaded, that is, doing only one thing at a time. This is determined based on the js execution environment, because in the browser, there are many DOM operations, if the operation of a DOM at the same time, it is easy to cause confusion, so in order to avoid the situation of the operation of the same DOM at the same time, JS chooses only one main thread to execute the code, to ensure the consistency of program execution. The single-threaded feature also applies to Node.
2.2 Tasks and queues in JavaScript
JavaScript is single-threaded, which means that all tasks have to be queued until the previous task is finished before the next task can be executed, but because IO devices (such as Ajax reading data from the network) are slow, they have to wait for the results to return before they can continue, which is very slow. So there are two kinds of tasks, synchronous tasks and asynchronous tasks. A synchronous task is a task that is queued on the main thread and is executed only after the previous task has completed. Asynchronous tasks do not enter the main thread, but enter a task queue. Tasks in the main thread can continue to execute, and asynchronous tasks in the task queue are notified to the main thread.
3. The browser event loop
3.1 Execution stack and event queue
When javascript code executes, different variables are stored in different locations in memory: in the heap and in the stack. There are objects in the heap. The stack holds basic type variables and Pointers to objects. When all synchronization tasks are executed on the main thread, they are arranged in a single place, forming an execution stack
When the browser JS engine parses this code, it will add the synchronization task order to the execution stack and execute it in turn. When the asynchronous task is encountered, it will not wait for the return result of the asynchronous task before executing the later task, but suspend the asynchronous task and continue to execute the synchronization task. When the asynchronous task returns the result, Add the callback events of asynchronous tasks to a Task Queue. The tasks in the Queue will not be executed immediately. Instead, the events in the event Queue will be executed in turn after all synchronous tasks have been executed.
The synchronization tasks are executed in sequence, the Event queue is executed in sequence after completion, and the synchronization tasks are executed after completion. In this way, an Event Loop is formed.
3.2 Macro Task and Micro Task
Asynchronous tasks are divided into macro tasks and microtasks. Microtasks are not executed in the order of the event queue, but in the order of microTask >macroTask. Macrotasks are executed after all microtasks in the queue are executed
Classification of macrotasks and microtasks
-
MacroTask: Script (overall code), setTimeout, setInterval, setImmediate (node only), I/O, UI Rendering
-
MicroTask: Process. NextTick (node only), Promises, object.Observe (deprecated), MutationObserver
For examplesetTimeout(()=>{
console.log(1)
})
Promise.resolve().then(function() {console.log(2)}) console.log(3) The result of execution is: 3 2 1 This is because the order of the event loop is: synchronize the code => microtask => macro taskCopy the code
4. The node of the event loop
-
Timers: This phase executes callbacks in the timer queue such as setTimeout() and setInterval().
-
I/O Callbacks: This phase performs almost all callbacks. But it does not include close events, timers, and callbacks to setImmediate().
-
Idle, prepare: This stage is for internal use only and can be ignored.
-
Poll: Waiting for a new I/O event. Node blocks here in some special cases.
-
The callback to check: setImmediate() is executed at this stage.
-
Close callbacks: for example socket.on(‘close’,…) The callback to this close event.
An example is (1) the difference between browser and Node execution ordersetTimeout(()=>{
console.log('timer1')
Promise.resolve().then(function() {
console.log('promise1')})})setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')})})Copy the code
Time1 promise1 time2 Promise2 A promise is a microtask, so after the first setTimeout, the promise is executed first.
The Node output: Time1 time2 PromisE1 Promise2 Since both time1 and time2 are in the Timers phase, the timers are run first. The promise callback is added to the Microtask queue. To execute the microTask queue.
For example (2) MicroTask queues and MacroTask queuessetTimeout(function () {
console.log(1);
});
console.log(2);
process.nextTick(() => {
console.log(3);
});
new Promise(function (resolve, rejected) {
console.log(4);
resolve()
}).then(res=>{
console.log(5);
})
setImmediate(function () {
console.log(6)
})
console.log('end');
Copy the code
The node output is 2, 4 end 3, 5, 1, 6. The first step is to execute the synchronization task 2, 4 end, NextTick :3 in the microTask queue, promise. Then :5, and setTimeout:1 in the macroTask queue, and setImmediate:6, because the Timer is better than the Check phase, so 1 goes to 6.