Event Queue

All tasks can be classified into synchronous tasks and asynchronous tasks. A synchronization task, as its name implies, is a task that is executed immediately. A synchronization task is usually executed directly into the main thread. Asynchronous tasks are asynchronously executed tasks, such as Ajax network requests and setTimeout timing functions. Asynchronous tasks are coordinated through the mechanism of task queue (first-in, first-out mechanism).

Synchronous and asynchronous tasks enter different execution environments respectively. Synchronous tasks enter the main thread, i.e. the main execution stack, and asynchronous tasks enter the task queue. If the task execution in the main thread is empty, it reads the corresponding task in the task queue and pushes the main thread to execute it. The repetition of this process is called an Event Loop.

In the event cycle, each cycle operation is called TICK. The key steps of the task processing model of each tick can be summarized as follows:

  • 1. Select the task that enters the queue first in this tick, and execute it (once) if there is one.
  • 2. Check whether Microtasks exist. If so, clear the Microtask Queue
  • 3. Update the render
  • 4. Repeat the preceding steps for the main thread

What are macro tasks and micro tasks

Macro task macrotasks:

  • setTimeout
  • setInterval
  • requestAnimationFrame
  • I/O
  • UI interaction events
  • SetImmediate (Node.js environment)
  • Script (whole code)

RequestAnimationFrame and setInterval comparison

Micro task microtasks:

  • Process.nexttick (node.js environment)
  • Promises
  • Object.observe (Monitor Object changes in JS in real time)
  • MutationObserver (Monitors changes made to the DOM tree)

Microtasks are executed in two cases:

  1. Task queue (MacroTask = Task Queue) is executed after a callback, provided that no other code is currently under execution.
  2. Execute at the end of each task.

In addition, during the processing of microtasks, new microtasks are added to the end of the queue and executed.

Look at the event loop in combination

  • The event loop starts with the macro task
  • An event loop has one or more task queues
  • Each event loop has a microTask queue
  • A macroTask queue is a task queue. A microTask queue is not a task queue
  • A task can be placed in a MacroTask queue or a microTask queue
  • When a task is put into a MicroTask or MacroTask queue, the preparation is complete and the task can be executed.

Start -> Remove the first task from the Task queue -> Remove all microTask tasks from the Task Queue -> Remove the next task from the Task Queue -> Remove all MicroTask tasks from the Task Queue again ->… And so on and so forth

The sample

The sample a

   setTimeout(function(){
        console.log(1)
    },0);
    new Promise(function(resolve){
        console.log(2)
        for( var i= 100000; i > 0 ; i-- ){
            i==1 && resolve()
        }
        console.log(3)
    }).then(function(){
        console.log(4)
    });
    console.log(5);
    
Copy the code

When setTimeout is encountered, its callback function console.log(1) is distributed to the macro task Event Queue. When a Promise is encountered, console.log(2) is executed, printing 2. The next step is to perform the for loop. Even if the for loop needs to be accumulated to 100,000, it is also in the execution stack. After the completion of the for loop, the state of Promise will be switched from depressing to resolve. Then push console.log(4) from the then callback to the microtask queue. Immediately execute immediately console.log(3), printing 3. When console.log(5) is encountered, output 5 completes the first round of execution with no code in progress. Execute console.log(4), Output 4: Console. log(1) is executed by macroTask setTimeout, and output 1: all queues are cleared

// 2 3 5 4 1
Copy the code

Example 2

console.log('script start');

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

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');

Copy the code

The whole script enters the main thread as the first macro task, encounters console.log, prints script start encounters setTimeout, and its callback function is distributed to the macro task Event Queue, meets Promise, The then function is placed in the microtask queue, named then1, and then function is placed in the microtask queue, named then2. Console. log is encountered, and script end is printed. If the microtask execution conditions are met, the task in the microtask is preferentially executed. Execute then1 and output promise1. Console. log(‘setTimeout’) is executed and setTimeout (‘setTimeout’) is executed. Then all queues are empty. completed

// script start
// script end
// promise1
// promise2
// setTimeout
Copy the code

Example 3

console.log('script start');

setTimeout(function() {
  console.log('timeout1');
}, 10);

new Promise(resolve => {
    console.log('promise1');
    resolve();
    setTimeout(() => console.log('timeout2'), 10);
}).then(function() {
    console.log('then1')
})

console.log('script end');
Copy the code

The event loop starts with the macroTask queue, which initially contains only one script task. When a task source is encountered, the task is first distributed to the corresponding task queue. So, similar to the above example, console.log is encountered and script start is printed; When the setTimeout task source is encountered, it is distributed to the task queue, denoted as timeout1. When a promise is encountered, the code in the new Promise executes immediately, outputs promise1, executes resolve, encounters setTimeout, dispatts it to the task queue, timemout2, then dispatts it to the microtask queue, Remember to then1; Then1 microtask queue, execute then1, print then1, then check the microtask queue, find that the microtask queue is empty, check the macro task queue, Execute timeout1 and print timeout1. Then execute timeout2, which prints timeout2. At this point, all queues are cleared, and execution is complete

// script start
// promise1
// script end
// then1
// timeout1
// timeout2
Copy the code

See flow chart

tips

JavaScript is a single-threaded language. Asynchronous operations are placed in an event loop queue waiting for the main execution stack. There is no special asynchronous execution thread.