通過一道常見的題目蚪拦,解釋事件循環(huán)和回調(diào)隊(duì)列機(jī)制
async function async1(){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1();
new Promise(function(resolve){
console.log('promise1')
resolve();
}).then(function(){
console.log('promise2')
})
console.log('script end')
在Chrome 66和node v10中杖剪,此題的正確輸出是:
script start
async1 start
async2
promise1
script end
promise2
async1 end
setTimeout
知識點(diǎn)
-
宏任務(wù)
一般包括包括:整體代碼script,setTimeout驰贷,setInterval盛嘿,setImmediate,MessageChannel -
微任務(wù)
一般包括:Promise括袒,process.nextTick -
執(zhí)行順序
首先在 宏任務(wù)的隊(duì)列(這個隊(duì)列也被叫做 task queue)中取出第一個任務(wù)次兆,執(zhí)行完畢后取出微任務(wù)隊(duì)列中的所有任務(wù)順序執(zhí)行;之后再取一個宏任務(wù)锹锰,周而復(fù)始芥炭,直至兩個隊(duì)列的任務(wù)都取完。 -
優(yōu)先級
?1. 宏任務(wù)的優(yōu)先級:主代碼塊 > setImmediate > MessageChannel > setTimeout / setInterval
?2. 微任務(wù)的優(yōu)先級:process.nextTick > Promise > MutationObserver -
Promise
?1. Promise一旦被定義恃慧,就會立即執(zhí)行园蝠。
?2. Promise的reject和resolve是異步執(zhí)行的回調(diào)。所以痢士,resolve()會被放到回調(diào)隊(duì)列中 -
async/await
?1. await執(zhí)行完后彪薛,會讓出線程。
?2. async標(biāo)記的函數(shù)會返回一個Promise對象
難點(diǎn)
為了便于理解,async1函數(shù)可以理解為以下方式:
async function async1(){
console.log('async1 start')
async2().then( () => {
console.log( 'async1 end ')
})
}
流程
- console.log('script start')輸出:script start
- setTimeout被放在最后調(diào)用
- 執(zhí)行async1函數(shù)善延,輸出async1 start训唱。然后,進(jìn)入async2函數(shù)挚冤,輸出async2况增,并返回Promise對象⊙档玻回到async1澳骤,由于await,讓出線程澜薄,async2函數(shù)返回的Promise放在回調(diào)隊(duì)列为肮。
- 新new了一個Promise對象,輸出promise1肤京。其中的resolve()被放在回調(diào)隊(duì)列颊艳。
- console.log('script end')輸出:script end
- 執(zhí)行回調(diào)隊(duì)列中,async1返回的Promise對象忘分,對象產(chǎn)生的resolve被放入對調(diào)隊(duì)列棋枕。這里不輸出任何值。
- 執(zhí)行回調(diào)隊(duì)列中妒峦,下方Promise顯式聲明的resolve重斑,輸出promise2。
- 執(zhí)行回調(diào)隊(duì)列中肯骇,由于async1函數(shù)返回的promise對象的resolve窥浪,輸出async1 end。
- 執(zhí)行回調(diào)隊(duì)列中笛丙,最后的setTimeout漾脂,輸出setTimeout
- 完成