而在JavaScript中有两种异步宏任务macro-task和微任务micro-task.
在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
常见的异步代码实现
macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, Promises(原生 Promise), Object.observe(api已废弃), MutationObserver
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for( var i=0 ; i<10000 ; i++ ) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
// 2 3 5 4 1
- 第一次整体代码进入macro-task。micro-task为空。
- macro-task执行整体代码,setTimeout加入下一次的macro-task。Promise执行打出2 3,then加入micro-task, 最后打出5。
- micro-task执行then被执行所以打出4。
- 重新执行macro-task所以打出1
Promise执行流程
- new Promise(func:(resolve, reject)=> void 0), 这里的func方法被同步执行。
- Promise 会有三种状态PENDING(执行),FULFILLED(执行成功),REJECTED(执行失败)。
- 在resolve,reject均未调用且未发生异常时状态为PENDING。
- resolve调用为FULFILLED,reject调用或者发生异常为REJECTED。
- 在给Promise实例调用then(callFulfilled, callRejected)来设置回调,状态不为PENDING时会根据状态调用callFulfilled和callRejected。
- then需要返回一个新的Promise实例.
- 状态为PENDING则会把callFulfilled和callRejected放入当前Promise实例的回调队列中,队列还会存储新的Promise实例。
- 在状态改变为FULFILLED或REJECTED时会回调当前Promise实例的队列。