Difference between microtask and macrotask within an event loop context

后端 未结 3 1271
一个人的身影
一个人的身影 2020-11-22 11:31

I\'ve just finished reading the Promises/A+ specification and stumbled upon the terms microtask and macrotask: see http://promisesaplus.com/#notes

I\'ve never heard

3条回答
  •  暖寄归人
    2020-11-22 12:20

    I think we can't discuss event loop in separation from stack, so:

    JS has three "stacks":

    • standard stack for all synchronous calls (one function calls another, etc)
    • microtask queue (or job queue or microtask stack) for all async operations with higher priority (process.nextTick, Promises, Object.observe, MutationObserver)
    • macrotask queue (or event queue, task queue, macrotask queue) for all async operations with lower priority (setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering)
    |=======|
    | macro |
    | [...] |
    |       |
    |=======|
    | micro |
    | [...] |
    |       |
    |=======|
    | stack |
    | [...] |
    |       |
    |=======|
    

    And event loop works this way:

    • execute everything from bottom to top from stack, and ONLY when the stack is empty, check what is going on in queues above
    • check micro stack and execute everything there (if required) with help of stack, one micro task after another until microtask queue is empty or don't require any execution and ONLY then check macro stack
    • check macro stack and execute everything there (if required) with help of stack

    Mico stack won't be touch if stack isn't empty. Macro stack won't be touch if micro stack isn't empty OR do not require any execution.

    To sum up: microtask queue is almost the same as macrotask queue but those tasks (process.nextTick, Promises, Object.observe, MutationObserver) have higher priority than macrotasks.

    Micro is like macro but with higher priority.

    Here you have "ultimate" code for understanding everything.

    console.log('stack [1]');
    setTimeout(() => console.log("macro [2]"), 0);
    setTimeout(() => console.log("macro [3]"), 1);
    
    const p = Promise.resolve();
    for(let i = 0; i < 3; i++) p.then(() => {
        setTimeout(() => {
            console.log('stack [4]')
            setTimeout(() => console.log("macro [5]"), 0);
            p.then(() => console.log('micro [6]'));
        }, 0);
        console.log("stack [7]");
    });
    
    console.log("macro [8]");
    
    /* Result:
    stack [1]
    macro [8]
    
    stack [7], stack [7], stack [7]
    
    macro [2]
    macro [3]
    
    stack [4]
    micro [6]
    stack [4]
    micro [6]
    stack [4]
    micro [6]
    
    macro [5], macro [5], macro [5]
    --------------------
    but in node in versions < 11 (older versions) you will get something different
    
    
    stack [1]
    macro [8]
    
    stack [7], stack [7], stack [7]
    
    macro [2]
    macro [3]
    
    stack [4], stack [4], stack [4]
    micro [6], micro [6], micro [6]
    
    macro [5], macro [5], macro [5]
    
    more info: https://blog.insiderattack.net/new-changes-to-timers-and-microtasks-from-node-v11-0-0-and-above-68d112743eb3
    */
    

提交回复
热议问题