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 用於申明一個 異步的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()中。

總結

  1. async 告訴程序這是一個異步,awiat 會暫停執行async中的代碼,等待await 表達式后面的結果,跳過async 函數,繼續執行后面代碼
  2. async 函數會返回一個Promise 對象,那么當 async 函數返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函數拋出異常時,Promise 的 reject 方法也會傳遞這個異常值
  3. await  操作符用於等待一個Promise 對象,並且返回 Promise 對象的處理結果(成功把resolve 函數參數作為await 表達式的值),如果等待的不是 Promise 對象,則用 Promise.resolve(xx) 轉化


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM