1. 程式人生 > >js async await 終極非同步解決方案

js 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()中

總結

  1. async 告訴程式這是一個非同步,awiat 會暫停執行async中的程式碼
  2. async 函式會返回一個Promise 物件,那麼當 async 函式返回一個值時,Promise 的 resolve 方法會負責傳遞這個值;當 async 函式丟擲異常時,Promise 的 reject 方法也會傳遞這個異常值
  3. await  操作符用於等待一個Promise 物件,並且返回 Promise 物件的處理結果(成功把resolve 函式引數作為await 表示式的值),如果等待的不是 Promise 物件,則返回該值本身 Promise.resolve(xx)