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

先來一道關於async/await、promise和setTimeout的執行順序的題目:

 1 async function async1() {
 2     console.log('async1 start');
 3     await async2();
 4     console.log('asnyc1 end');
 5 }
 6 async function async2() {
 7     console.log('async2');
 8 }
 9 console.log('script start');
10 setTimeout(() => {
11     console.log('setTimeOut');
12 }, 0);
13 async1();
14 new Promise(function (reslove) {
15     console.log('promise1');
16     reslove();
17 }).then(function () {
18     console.log('promise2');
19 })
20 console.log('script end');

執行結果:

1 script start
2 async1 start
3 async2
4 promise1
5 script end
6 asnyc1 end
7 promise2
8 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執行須要知足兩個條件:node

  1. 主進程必須是空閒的狀態,若是到時間了,主進程不空閒也不會執行你的回掉函數 
  2. 這個回掉函數須要等到插入異步隊列時前面的異步函數都執行完了,纔會執行 

簡單理解就是:promise

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

promise、async/await

  1. 首先,new Promise是同步的任務,會被放到主進程中去當即執行。而.then()函數是異步任務會放到異步隊列中去,那何時放到異步隊列中去呢?當你的promise狀態結束的時候,就會當即放進異步隊列中去了。
  2. 帶async關鍵字的函數會返回一個promise對象,若是裏面沒有await,執行起來等同於普通函數;若是沒有await,async函數並無很厲害是否是
  3. await 關鍵字要在 async 關鍵字函數的內部,await 寫在外面會報錯;await如同他的語意,就是在等待,等待右側的表達式完成。此時的await會讓出線程,阻塞async內後續的代碼,先去執行async外的代碼。等外面的同步代碼執行完畢,纔會執行裏面的後續代碼。就算await的不是promise對象,是一個同步函數,也會等這樣操做

步入正題:

根據圖片顯示咱們來整理一下流程:

  1. 執行console.log('script start'),輸出script start;
  2. 執行setTimeout,是一個異步動做,放入宏任務異步隊列中;
  3. 執行async1(),輸出async1 start,繼續向下執行;
  4. 執行async2(),輸出async2,並返回了一個promise對象,await讓出了線程,把返回的promise加入了微任務異步隊列,因此async1()下面的代碼也要等待上面完成後繼續執行;
  5. 執行 new Promise,輸出promise1,而後將resolve放入微任務異步隊列;
  6. 執行console.log('script end'),輸出script end;
  7. 到此同步的代碼就都執行完成了,而後去微任務異步隊列裏去獲取任務
  8. 接下來執行resolve(async2返回的promise返回的),輸出了async1 end。
  9. 而後執行resolve(new Promise的),輸出了promise2。
  10. 最後執行setTimeout,輸出了settimeout。

參考博客:https://blog.csdn.net/yun_hou/article/details/88697954async

相關文章
相關標籤/搜索