Node.js 执行顺序初探

2019-05-17  本文已影响0人  JerryShieh

Concept

eventloop 概览

   ┌───────────────────────────┐
┌─>│           timers          │    (this phase executes callbacks scheduled by setTimeout() and setInterval())
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │    (executes I/O callbacks deferred to the next loop iteration.)
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │    (only used internally)
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │ (retrieve new I/O events; execute I/O related callbacks)
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │    (setImmediate() callbacks are invoked here)
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │    (some close callbacks, e.g. socket.on('close', ...))
   └───────────────────────────┘

详情请参考 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Macrotask and Microtask

参考 https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context:

eventloop的一次循环,会从 macrotask queue取出一个任务, 任务完成后,所有microtask queue的微任务都会被处理完,然后继续从macrotask queue取任务……微任务在被处理的过程中可以创建其他的微任务,并且这些微任务也会被加入 microtask queue并被一一执行。

如上所述,如果一个微任务不断创建新的微任务,则可能会对其他宏任务造成“饥饿”现象,因为微任务队列很难被清空。

Examples:
macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering
microtasks: process.nextTick, Promises, Object.observe, MutationObserver

Example

JS code

console.log('main thread start ...');
setTimeout(() => console.log('Timeout1'), 0);   // Macro task queue
let promiseF = () => new Promise(resolve => setTimeout(() => resolve('Timeout3'), 0));
let asyncF = async () => console.log(await promiseF());
asyncF();   // For async will wrap the result with promise, "console.log(await promiseF())"" enters Micro task

let p1 = Promise.resolve('p1');
let p2 = Promise.resolve('p2');

p1.then(r => {
    console.log(r); // p1
    setTimeout(() => console.log('Timeout2'), 0);   // Macro task queue
    const p3 = Promise.resolve('p3');
    p3.then(console.log);   // p3
}); // Micro task queue

p2.then(console.log);   // p2
setTimeout(() => console.log('Timeout4'), 0); // Macro task
console.log('main thread end.');

上面程序运行的结果如下:

main thread start ...
main thread end.
p1
p2
p3
Timeout1
Timeout4
Timeout2
Timeout3

执行顺序

因此,最终的打印结果是

main thread start ...
main thread end.
p1
p2
p3
Timeout1
Timeout4
Timeout2
Timeout3
上一篇下一篇

猜你喜欢

热点阅读