天天看點

關于async/await、promise和setTimeout執行順序

前段時間上司給我們出了一道題,關于async/await、promise和setTimeout的執行順序,網上查了查資料,這是頭條的一道筆試題,記錄一下,加深了解。

題目如下:

async function async1() {
  console.log('async1 start');
  await async2();
  console.log('asnyc1 end');
}
async function async2() {
  console.log('async2');
}
console.log('script start');
setTimeout(() => {
  console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
  console.log('promise1');
  reslove();
}).then(function () {
  console.log('promise2');
})
console.log('script end');      

執行結果:

script start

async1 start

async2

promise1

script end

asnyc1 end

promise2

setTimeOut

首先,我們先來了解一下基本概念:

js EventLoop 事件循環機制:

JavaScript的事件分兩種,宏任務(macro-task)和微任務(micro-task)

宏任務:包括整體代碼script,setTimeout,setInterval

微任務:Promise.then(非new Promise),process.nextTick(node中)

事件的執行順序,是先執行宏任務,然後執行微任務,這個是基礎,任務可以有同步任務和異步任務,同步的進入主線程,異步的進入Event Table并注冊函數,異步事件完成後,會将回調函數放入Event Queue中(宏任務和微任務是不同的Event Queue),同步任務執行完成後,會從Event Queue中讀取事件放入主線程執行,回調函數中可能還會包含不同的任務,是以會循環執行上述操作。

注意: setTimeOut并不是直接的把你的回掉函數放進上述的異步隊列中去,而是在定時器的時間到了之後,把回掉函數放到執行異步隊列中去。如果此時這個隊列已經有很多任務了,那就排在他們的後面。這也就解釋了為什麼setTimeOut為什麼不能精準的執行的問題了。setTimeOut執行需要滿足兩個條件:

1. 主程序必須是空閑的狀态,如果到時間了,主程序不空閑也不會執行你的回掉函數 

2. 這個回掉函數需要等到插入異步隊列時前面的異步函數都執行完了,才會執行 

 上面是比較官方的解釋,說一下自己的了解吧:

了解了什麼是宏任務和微任務,就好了解多了,首先執行 宏任務 => 微任務的Event Queue => 宏任務的Event Queue

promise、async/await

首先,new Promise是同步的任務,會被放到主程序中去立即執行。而.then()函數是異步任務會放到異步隊列中去,那什麼時候放到異步隊列中去呢?當你的promise狀态結束的時候,就會立即放進異步隊列中去了。

帶async關鍵字的函數會傳回一個promise對象,如果裡面沒有await,執行起來等同于普通函數;如果沒有await,async函數并沒有很厲害是不是

await 關鍵字要在 async 關鍵字函數的内部,await 寫在外面會報錯;await如同他的語意,就是在等待,等待右側的表達式完成。此時的await會讓出線程,阻塞async内後續的代碼,先去執行async外的代碼。等外面的同步代碼執行完畢,才會執行裡面的後續代碼。就算await的不是promise對象,是一個同步函數,也會等這樣操作

步入正題:

 根據圖檔顯示我們來整理一下流程:

繼續閱讀