异步执行机制
- (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
- (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
- (3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
- (4)主线程不断重复上面的第三步。
宏任务(task)与微任务(job)
宏任务有:
- setTimeout,
- setInterval,
- setImmediate (Node独有),
- requestAnimationFrame (浏览器独有),
- I/O,
- UI rendering (浏览器独有)
微任务有:
- process.nextTick (Node独有)
- Promise
- Object.observe
- MutationObserver
event loop
1 执行所有的同步script语句,碰到回调函数等异步语句时放入相应的任务队列(宏、微)
2 当当前执行栈为空时,才会去处理异步任务:
3 先将微任务队列清空,在执行微任务时新产生的微任务会立即被加入微任务队列并清空
4 再执行宏队列中的任务,若在执行宏任务时产生新的微任务,会加入微队列中并在每个宏任务执行的间隙清空当前微队列

栗子
console.log(1); //同步任务
setTimeout(() => { //宏任务
console.log(2);
Promise.resolve().then(() => { //执行宏任务时产生的微任务
console.log(3)
});
});
new Promise((resolve, reject) => {
console.log(4) //同步任务
resolve(5)
}).then((data) => {
console.log(data); //微任务
Promise.resolve().then(() => {
console.log(6) //微任务
}).then(() => {
console.log(7) //微任务
setTimeout(() => {
console.log(8) //微任务里的宏任务
}, 0);
});
})
setTimeout(() => {
console.log(9); //宏任务
})
console.log(10); //同步任务
顺序:所有同步任务=>当前微任务队列=>一个宏任务=>当前微任务队列=>...=>执行栈为空
结果:1,4,10,5,6,7,2,3,9,8
nodejs中的宏队列与微队列
NodeJS中宏队列主要有4个,回调事件主要位于4个macrotask queue中:
- Timers Queue
- IO Callbacks Queue
- Check Queue
- Close Callbacks Queue
NodeJS中微队列主要有2个:
- Next Tick Queue:是放置process.nextTick(callback)的回调任务的
- Other Micro Queue:放置其他microtask,比如Promise等
event loop过程:
1 执行所有的同步代码
2 执行栈为空时,执行微队列,先执行所有Next Tick Queue中的所有任务,再执行Other Microtask Queue中的所有任务。
3 微队列清空后开始执行宏队列,每次执行一个宏队列,间隙中执行当前微队列
4 顺序:同步任务=>两个微队列=>Timers Queue ->两个微队列-> I/O Queue -> 两个微队列 -> Check Queue -> 两个微队列 -> Close Callback Queue -> 两个微队列 -> Timers Queue ......