preface

Js is single-threaded, and all tasks are executed in a queue. The next task is executed only after the previous task is finished. If a time-consuming task is encountered, the next task has to wait for a long time.

Js tasks are divided into synchronous tasks and asynchronous tasks. Asynchronous tasks include micro tasks and macro tasks. The execution time of micro tasks is earlier than that of macro tasks. The code running JS forms a main thread and a task queue, which includes a microtask queue and a macro task queue. During the execution of the main thread, the micro task and macro task enter the corresponding queue respectively.

First, synchronous tasks enter the main thread for execution, while asynchronous tasks enter the microtask queue and macro task queue respectively. When all synchronization tasks in the main thread are completed, the micro tasks in the micro task queue will enter the main thread for execution until the queue is empty, and then the macro task will be executed.

During the execution of the main thread, the micro task and macro task enter the corresponding queue at the same time. After the execution of the main thread, the tasks are successively taken from the micro task queue and macro task queue for execution. The above process is repeated repeatedly, namely the Event Loop.

Macrotask and Microtask

Asynchronous tasks are divided into macrotasks and microtasks according to their execution priorities. The execution timing of microtasks is earlier than that of macro tasks. 1. Macrotask

Macrotask includes: setTimeout, setInterval, setImmediate (Node only), requestAnimationFrame (browser only), I/O, UI Rendering (browser only)

2. Microtasks

Microtasks include: Promise, Object.observe, MutationObserver, and Process. nextTick(Node only)

Macrotask, Microtask, and DOM rendering order

Microtask executes before DOM rendering and Macrotask executes after DOM rendering. Alert blocks threads, including GUI threads for page rendering, to verify the order of microtasks, macro tasks, and DOM node rendering. The index.html file

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div id="box">
    </div>
    <script>
        let boxDom = document.getElementById("box")
        boxDom.innerHTML="<H1>Hello</H1>"
        setTimeout(()=>{
            console.log('setTimeout')
            alert('setTimeout')
        })
        Promise.resolve().then(()=>{
            console.log('promise')
            alert('promise')
        })
    </script>
</body>
</html>
Copy the code

The microtask Promise is executed before DOM rendering.

After the DOM renders, the macro task Promise is executed.

Event Loop for browser and Node

1. Browser (1) the overall code script enters the main thread and starts execution. (2) During the execution of the main thread, asynchronous tasks are put into the task queue, which stores two types of asynchronous tasks: macro task queue and micro task queue. (3) After the completion of the synchronization task, take out the microtask execution from the microtask queue successively. If new microtasks are generated during the execution of the microtask, the new microtasks are added to the end of the queue. After the execution of (4) the microtask queue is completed, Fetch the next macro task from the macro task queue and execute (5) loop (3) – > (4) until all tasks are completed

2. Before node11: (1) Execute all tasks in a phase (2) execute contents in the nextTick queue (3) then execute contents in the microtask queue



Please refer to:Nodejs.org/zh-cn/docs/…

After the node11:

In line with the browser, the sync task is executed, the microtask queue is looping, and the macro task is executed… . The cycle repeats.

The sample

SetTimeout and Promise are used as representatives of microtasks and macro tasks, respectively.

  1. Microtasks and macro tasks run separately
console.log('script start'); setTimeout(() => { console.log('setTimeout1'); }, 0); Promise.resolve().then(()=>{ console.log('promise1'); }) setTimeout(() => { console.log('setTimeout2'); }, 0); Promise.resolve().then(()=>{ console.log('promise2'); }) console.log('script end'); // Script start //script end //promise1 //promise2 //setTimeout1 //setTimeout2Copy the code

Execution sequence: (1) Execute synchronization tasks, and output: script start script end At the same time, promise1 and promise2 enter the microtask queue, setTimeout1 and setTimeout2 enter the macro task queue. (2) execute the microtask queue periodically, and output: Promise1 Promise2 (3) Executes a macro task with setTimeout1 (4) Executes a macro task with setTimeout2 2. Microtasks include microtasks, and macro tasks include macro tasks

console.log('script start'); setTimeout(() => { console.log('setTimeout1'); setTimeout(()=>{ console.log('setTimeout1-1'); })}, 0); Promise.resolve().then(()=>{ console.log('promise1'); Promise.resolve().then(()=>{ console.log('promise1-1'); }) }) setTimeout(() => { console.log('setTimeout2'); setTimeout(()=>{ console.log('setTimeout2-2'); })}, 0); Promise.resolve().then(()=>{ console.log('promise2'); Promise.resolve().then(()=>{ console.log('promise2-2'); }) }) console.log('script end'); // Script start // script end // promise1 // promise2 // promisE1-1 // promise2-2 // setTimeout1 // setTimeout2 // setTimeout1-1 // setTimeout2-1Copy the code

Execution sequence: (1) Execute synchronization tasks. Output: Note: setTimeout1, setTimeout1, setTimeout1, setTimeout1, setTimeout1, setTimeout1 SetTimeout2 Enters the macro task queue. (2) Run the micro task queue, and the output is promisE1 promise2 promisE1-1 promisE2-2. (3) Run the macro task queue, and the output is: SetTimeout1 setTimeout2 At the same time setTimeout1-1, setTimeout2-1 enter the macro task queue. (4) Execute the macro task queue, and output: setTimeout1-1 setTimeout2-1 3. Microtasks and macro tasks are included interleaved

console.log('script start'); setTimeout(() => { console.log('setTimeout1'); setTimeout(()=>{ console.log('setTimeout2'); }) Promise.resolve().then(()=>{ console.log('promise1'); })}, 0); Promise.resolve().then(()=>{ console.log('promise2'); Promise.resolve().then(()=>{ console.log('promise3'); }) setTimeout(()=>{ console.log('setTimeout3'); }) }) setTimeout(() => { console.log('setTimeout4'); setTimeout(()=>{ console.log('setTimeout5'); }) Promise.resolve().then(()=>{ console.log('promise4'); })}, 0); Promise.resolve().then(()=>{ console.log('promise5'); Promise.resolve().then(()=>{ console.log('promise6'); }) setTimeout(()=>{ console.log('setTimeout6'); }) }) console.log('script end'); // Script start // script end // promise2 // promise5 // promise3 // promise6 // setTimeout1 // promise1 // setTimeout4 // promise4 // setTimeout3 // setTimeout6 // setTimeout2 // setTimeout5Copy the code

Execution sequence: (1) Execute synchronization tasks. Output: SetTimeout1 and setTimeout4 enter the macro task queue. The following output is displayed: SetTimeout3, setTimeout6 Enter the macro task queue (3) and execute the macro task queue setTimeout1 in step (1). SetTimeout1 promise1 setTimeout2 Enters a new macro task queue (4) and executes setTimeout4 in step (1). SetTimeout4 promise4 setTimeout5 Enters a new macro task queue (5) and executes the macro task queue setTimeout3 of step (2), output: setTimeout3 (6) And setTimeout6 of step (2) SetTimeout6 (7) executes the macro task queue setTimeout2 of step (3) with output: setTimeout2 (8) executes the macro task queue setTimeout4 of step (4) with output: setTimeout5