而在JavaScript中有兩種異步宏任務(wù)macro-task和微任務(wù)micro-task.
在掛起任務(wù)時,JS 引擎會將所有任務(wù)按照類別分到這兩個隊列中,首先在 macrotask 的隊列(這個隊列也被叫做 task queue)中取出第一個任務(wù),執(zhí)行完畢后取出 microtask 隊列中的所有任務(wù)順序執(zhí)行;之后再取 macrotask 任務(wù),周而復(fù)始,直至兩個隊列的任務(wù)都取完。
常見的異步代碼實現(xiàn)
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
- 第一次整體代碼進(jìn)入macro-task。micro-task為空。
- macro-task執(zhí)行整體代碼,setTimeout加入下一次的macro-task。Promise執(zhí)行打出2 3,then加入micro-task, 最后打出5。
- micro-task執(zhí)行then被執(zhí)行所以打出4。
- 重新執(zhí)行macro-task所以打出1
Promise執(zhí)行流程
- new Promise(func:(resolve, reject)=> void 0), 這里的func方法被同步執(zhí)行。
- Promise 會有三種狀態(tài)PENDING(執(zhí)行),F(xiàn)ULFILLED(執(zhí)行成功),REJECTED(執(zhí)行失敗)。
- 在resolve,reject均未調(diào)用且未發(fā)生異常時狀態(tài)為PENDING。
- resolve調(diào)用為FULFILLED,reject調(diào)用或者發(fā)生異常為REJECTED。
- 在給Promise實例調(diào)用then(callFulfilled, callRejected)來設(shè)置回調(diào),狀態(tài)不為PENDING時會根據(jù)狀態(tài)調(diào)用callFulfilled和callRejected。
- then需要返回一個新的Promise實例.
- 狀態(tài)為PENDING則會把callFulfilled和callRejected放入當(dāng)前Promise實例的回調(diào)隊列中,隊列還會存儲新的Promise實例。
- 在狀態(tài)改變?yōu)镕ULFILLED或REJECTED時會回調(diào)當(dāng)前Promise實例的隊列。