js async await 終極非同步解決方案
既然有了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 wait 的簡寫。所以應該很好理解 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會暫停當前async 函式執行,並且await 後面是一個表示式,即這個await 等待的是一個表示式(這個表示式返回promise 物件或者一個具體的值):
這個表示式如果返回的是一個Promise 物件,那麼其回撥的 resolve函式引數作為 await 表示式的值,如果這個Promise rejected 了,await 表示式會把 Promise 的異常丟擲。
這個表示式如果返回的是一個常量,那麼會把這個常量轉為Promise.resolve(xx),同理如果沒有返回值也是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 鏈,如下使用async awiat 巢狀情況如下
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中的程式碼
- async 函式會返回一個Promise 物件,那麼當 async 函式返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函式丟擲異常時,Promise 的 reject 方法也會傳遞這個異常值
- await 操作符用於等待一個Promise 物件,並且返回 Promise 物件的處理結果(成功把resolve 函式引數作為await 表示式的值),如果等待的不是 Promise 物件,則返回該值本 Promise.resolve(xx)