前言
對於promise、async和await的執行順序,很多人都容易弄混,也有很多人只願意在程序中運用一種,比如我只使用promise,不使用async和await;也有只用async和await,而不是用promise。所以現在來為大家講講一起共存需要注意寫什么?
示例
下面這段promise、async和await代碼,請問控制台打印的順序?
上述,在Chrome 66
和node v10
中,正確輸出是:
知識點
顯然,這考察的是js中的事件循環和回調隊列。注意以下幾點:
* Promise
優先於setTimeout
宏任務。所以,setTimeout
回調會在最后執行。
* Promise
一旦被定義,就會立即執行。
* Promise
的reject
和resolve
是異步執行的回調。所以,resolve()
會被放到回調隊列中,在主函數執行完和setTimeout
前調用。
* await
執行完后,會讓出線程。async
標記的函數會返回一個Promise
對象
難點
最令人困惑的,就是async1 end
在promise2
之后輸出
在函數async1
中,執行promise
(由於async2
是async
標記的函數,所以默認返回promise
對象)會發現resolve()
,然后放入回調隊列。
接着執行下方的new Promise
中的resolve()
輸出promise2
,再回來輸出async1 end
。
其中,async1
函數可以寫成以下方式(便於理解):
流程
1. `console.log('script start')`輸出:`script start`
2. `setTimeout`被放在最后調用
3. 執行`async1`函數,輸出`async1 start`。然后,進入`async2`函數,輸出`async2`,並返回`Promise`對象。回到`async1`,由於`await`,讓出線程,`async2`函數返回的`Promise`放在**回調隊列**。
4. 新new了一個`Promise`對象,輸出`promise1`。其中的`resolve()`被放在回調隊列。
5. `console.log('script end')`輸出:`script end`
6. 執行回調隊列中,`async1`返回的`Promise`對象,對象產生的`resolve`被放入對調隊列。這里不輸出任何值。
7. 執行回調隊列中,下方`Promise`顯式聲明的`resolve`,輸出`promise2`。
8. 執行回調隊列中,由於`async1`函數返回的`promise`對象的`resolve`,輸出`async1 end`。
9. 執行回調隊列中,最后的`setTimeout`,輸出`setTimeout`
10. finish