既然有了promise 為什么還要有async await ? 當然是promise 也不是完美的異步解決方案,而 async await 的寫法看起來更加簡單且容易理解。
回顧 Promise
Promise 對象用於表示一個異步操作的最終狀態(完成或失敗),以及其返回的值。
Promise
對象是由關鍵字 new
及其構造函數來創建的。構造函數會,把一個叫做“處理器函數”(executor function)的函數作為它的參數。這個“處理器函數”接受兩個函數resolve
和 reject
作為其參數。當異步任務順利完成且返回結果值時,會調用 resolve
函數,而當異步任務失敗且返回失敗原因(通常是一個錯誤對象)時,會調用reject
函數。
promise 狀態
pending:初始狀態,既不是成功,也不是失敗狀態
fulfilled:操作成功
rejected:操作失敗
promise demo
1 var promise1 = new Promise(function(resolve, reject) { 2 setTimeout(function() { 3 resolve('foo'); 4 }, 300); 5 }); 6 promise1.then(function(value) { 7 console.log(value); 8 // foo 9 }); 10 console.log(promise1); 11 // [object Promise]
通過外部then() 方法來綁定成功、失敗的回調函數,有沒有感覺這個跟之前的ajax 差不多,只不過是我們把回調丟到了then() 中,這個then 並且支持鏈式操作,即如果存在多個嵌套那么也就是不斷的then()。
async await 字面理解
先從字面意思來理解,async 是“異步”的意思,而 await 是等待的意思。所以應該很好理解 async 用於申明一個 異步的function(實際上是async function 對象),而 await 用於等待一個異步任務執行完成的的結果。
並且 await 只能出現在 async 函數中。
async await demo
1 在api中,把結果return 出去 2 export async function getRetailUnitPrice () { 3 const reqBody = await get('/race/spot/racespot/enter/dayahead') 4 return reqBody 5 }
1 vuex 中把結果commit: 2 // 發電:日前機組中標出力 3 async getRealTimeRetailUnitPrice ({commit}) { 4 const {output} = await getRetailUnitPrice() 5 commit(types.PLANT_REALTIME_DAYAHEAD, {output}) 6 }
1 在vue中代碼 2 try {this.$store.dispatch('getRealTimeRetailUnitPrice') 3 } catch (e) { 4 this.$Message.error(e) 5 }
async、await 如何執行
async 告訴程序這是一個異步操作,await 是一個操作符,即 await 后面是一個表達式。
async 的返回值
1 // async 2 async function testAsync() { 3 return "hello async"; 4 } 5 const data = testAsync(); 6 console.log(data);
如圖所示:
當調用一個 async 函數時,會返回一個 Promise 對象。根據mdn的解釋
當這個 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;
當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值。async 函數中可能會有 await 表達式,await表達式會使 async 函數暫停執行,直到表達式中的 Promise 解析完成后繼續 執行 async中await 后面的代碼並返回解決結果。
注意, await 關鍵字僅僅在 async function中有效
既然返回的是Promise 對象,所以在最外層不能用 await 獲取其返回值的情況下,那么肯定可以用原來的方式:then() 鏈來處理這個 Promise 對象 如
1 // async 2 async function testAsync() { 3 return "hello async"; 4 } 5 let data = testAsync().then( (data) => { 6 console.log(data) // hello async 7 return data 8 }); 9 console.log(data);
如果 async 函數沒有返回值,又怎么樣呢?很容易想到,它會返回 Promise.resolve(undefined)。
聯想一下 Promise 的特點無等待,所以在沒有 await 的情況下執行 async 函數,它會立即執行,返回一個 Promise 對象,並且,絕不會阻塞后面的語句。
await 操作符
MDN 是這樣描述 await 的:
await 表達式會暫停當前 async function 的執行,等待 Promise 處理完成。若 Promise 正常處理(fulfilled),其回調的resolve函數參數作為 await 表達式的值,繼續執行async function。若 Promise 處理異常(rejected),await 表達式會把 Promise 的異常原因拋出。另外,如果 await 操作符后的表達式的值不是一個 Promise,則返回該值本身。
阮一峰老師的解釋我覺得更容易理解:
async 函數返回一個 Promise 對象,當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再接着執行函數體內后面的語句。
按照mdn解釋 await會暫停當前async 函數執行,並且await 后面是一個表達式,即這個await 等待的是一個表達式(這個表達式返回promise 對象或者一個具體的值):
- 假如這個表達式如果返回的是一個Promise 對象, 那么它的返回值,實際上就是 Promise 的回調函數 resolve 的參數,如果這個Promise rejected 了,await 表達式會把 Promise 的異常拋出。
- 假如這個表達式如果返回的是一個常量,那么會把這個常量轉為Promise.resolve(xx),同理如果沒有返回值也是Promise.resolve(underfind)
1 async function testAwait() { 2 const data = await "hello await"; 3 console.log(data) 4 return data 5 }
輸出 “hello await”
返回promose 對象,成功狀態
1 function say() { 2 return new Promise(function(resolve, reject) { 3 setTimeout(function() { 4 let age = 26 5 resolve(`hello, joel。今年我 ${age} 歲`); 6 }, 1000); 7 }); 8 } 9 10 async function demo() { 11 const v = await say(); // 輸出:hello, joel。今年我 26 歲 等待這個say 的異步,如果成功把回調 resole 函數的參數作為結果 12 console.log(v); 13 } 14 demo();
返回promise 對象,失敗狀態
1 function say() { 2 return new Promise(function(resolve, reject) { 3 setTimeout(function() { 4 let age = 26 5 reject(`hello, joel,發生了異常。今年我 ${age} 歲`); 6 }, 1000); 7 }); 8 } 9 async function demo() { 10 try { 11 const v = await say(); // 輸出:hello, joel,發生了異常。今年我 26 歲 等待這個say 的異步,如果成功把回調 resole 函數的參數作為結果 12 console.log(v); 13 } catch (e) { 14 console.log(e) 15 } 16 } 17 demo();
async/await 相比原來的Promise的優勢在於處理 then 鏈,不必把回調嵌套在then中,只要await 即可,如
1 function sing() { 2 return new Promise(function(resolve, reject) { 3 setTimeout(function() { 4 resolve(`來一首好聽的歌吧~~~`); 5 }, 1000); 6 }); 7 } 8 async function demo() { 9 try { 10 const v = await say(); 11 const s = await sing(); 12 console.log(v); // 輸出:hello, joel。今年我 26 歲 13 console.log(s) // 來一首好聽的歌吧~~~ 14 } catch (e) { 15 console.log(e) 16 } 17 } 18 demo();
如果使用原來的Promise 就是把回調放在then()中。
總結
- async 告訴程序這是一個異步,awiat 會暫停執行async中的代碼,等待await 表達式后面的結果,跳過async 函數,繼續執行后面代碼
- async 函數會返回一個Promise 對象,那么當 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值
- await 操作符用於等待一個Promise 對象,並且返回 Promise 對象的處理結果(成功把resolve 函數參數作為await 表達式的值),如果等待的不是 Promise 對象,則用 Promise.resolve(xx) 轉化