一個函數如果加上async
,那么該函數就會返回一個Promise
async function test() { return "1" } console.log(test()) // -> Promise {<resolved>: "1"}
async
就是將函數返回值使用Promise.resolve()
包裹了下,和then
中處理返回值一樣,並且await
只能配套async
使用
async function test() { let value = await sleep() }
async
和await
可以說是異步終極解決方案了,相比直接使用Promise
來說,優勢在於處理then
的調用鏈,能夠更清晰准確的寫出代碼,畢竟寫一大堆then
也很惡心,並且也能優雅地解決回調地獄問題。當然也存在一些缺點,因為await
將異步代碼改造成了同步代碼,如果多個異步代碼沒有依賴性卻使用了await
會導致性能上的降低。
async function test() { // 以下代碼沒有依賴性的話,完全可以使用 Promise.all 的方式 // 如果有依賴性的話,其實就是解決回調地獄的例子了 await fetch(url) await fetch(url1) await fetch(url2) }
下面來看一個使用await
的例子:
let a = 0 let b = async () => { a = a + await 10 console.log('2', a) // -> '2' 10 } b() a++ console.log('1', a) // -> '1' 1
對於以上代碼你可能會有疑惑,讓我來解釋下原因
- 首先函數
b
先執行,在執行到await 10
之前變量a
還是 0,因為await
內部實現了generator
,generator
會保留堆棧中東西,所以這時候a = 0
被保存了下來 - 因為
await
是異步操作,后來的表達式不返回Promise
的話,就會包裝成Promise.reslove(返回值)
,然后會去執行函數外的同步代碼 - 同步代碼執行完畢后開始執行異步代碼,將保存下來的值拿出來使用,這時候
a = 0 + 10
上述解釋中提到了await
內部實現了generator
,其實await
就是generator
加上Promise
的語法糖,且內部實現了自動執行generator
。如果你熟悉 co 的話,其實自己就可以實現這樣的語法糖。