標籤:

[翻譯]在 Angular 中使用 async-await 特性

在 Angular 中使用 async-await 特性

原文鏈接:

https://medium.com/@balramchavan/using-async-await-feature-in-angular-587dd56fdc77?

medium.com

更新:在Angular的新版本中,我們不需要擔心 http()[1] 返回的 promise。儘管如此,我們仍然可以使用 async-await 來實現其他基於 promise 的邏輯。

在 JavaScript 中,用 Promises 和回調函數編寫非同步代碼。

在 Angular 應用中,我們可以使用 Rx.js 利用 Observables, Subject, BehaviorSubject 等強大的功能,以優雅的方式編寫非同步代碼。

ECMA 腳本草案的最新版本,JavaScript 開始支持 async-await

ECMAScript Latest Draft (ECMA-262)

如果你有 c# 的開發背景,你可能知道從 c# 5開始就支持 async-await 特性了。

Async-await

按照MDN

當調用非同步函數時,它返回一個 Promise 。當 async 函數返回一個值時,將使用返回的值 resolved Promise。當非同步函數拋出異常或某個值時,將使用拋出的值 rejected promise。 非同步函數可以包含一個 await 表達式,該表達式掛起非同步函數的執行並等待傳遞的 Promise 的解析,然後恢復非同步函數的執行並返回 resolved 後的值。

簡單地說,您將有機會以同步方式編寫非同步代碼。

例1

讓我們考慮一個簡單的例子。一個函數,它在兩秒後返回一個承諾解析並返回作為參數傳遞的值。

resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}

使用 promise ,我們可以使用 then 回調函數獲得值。

getValueWithPromise() {
this.resolveAfter2Seconds(20).then(value => {
console.log(`promise result: ${value}`);
});
console.log(I will not wait until promise is resolved);
}

在上述情況下,第5行 console.log() 應在第3行 console.log() 之前執行。這是Promise的基礎能力。

現在,我們看下 async-await 的用法

async getValueWithAsync() {
const value = <number>await this.resolveAfter2Seconds(20);
console.log(`async result: ${value}`);
}

這裡有幾點需要注意:

第1行-函數的前綴是 async 關鍵字。如果函數有 wait 關鍵字,則必須使用此前綴。

第2行-我們沒有在 promise 函數之後調用 .then() 回調函數。相反,我們用 await 關鍵字作為函數調用的前綴。此關鍵字不允許執行下一個代碼塊。這意味著,只有當 promise 像同步函數調用一樣在第2行解析時,第3行的 console.log() 才會被列印出來。

由於我們使用 Typescript,所以需要將 promise 返回值轉成特定類型,因此轉成第2行的類型。

例2

讓我們嘗試使用基於 promise 的方法添加兩個數字。

addWithPromise() {
this.resolveAfter2Seconds(20).then(data1 => {
let result1 = <number>data1;
this.resolveAfter2Seconds(30).then(data2 => {
let result2 = <number>data2;
this.additionPromiseResult = result1 + result2;
console.log(`promise result: ${this.additionPromiseResult}`);
});
});
}

在實際應用程序中,很常見的情況是最後出現嵌套的 promise-then 結構(回調地獄)。我們上面的代碼就出現了2級嵌套。想像一下用捕獲的變數和異常(如果有的話)進行7-8級嵌套。可怕的不是嗎?

現在我們使用基於 async 的方法

async addWithAsync() {
const result1 = <number>await this.resolveAfter2Seconds(20);
const result2 = <number>await this.resolveAfter2Seconds(30);
this.additionAsyncResult = result1 + result2;
console.log(`async result: ${this.additionAsyncResult}`);
}

比較一下代碼的簡潔性。這兩種方法將給我們相同的結果,但在代碼可讀性方面,維護 async-await 優於經典的 promise-then 方法。

消費Http REST APIs

到目前為止,我們討論了一些簡單的例子。在 Angular 應用中,我們可以使用 Http[2] (即將過時)或 HttpClient 服務來獲取 REST 數據。默認情況下,HttpClient 類的 get()put()delete()post() 方法返回 Observable<T> 。這個結果集可以通過 subscribe 方法或使用 RxJs 中的 toPromise() 操作符來使用。

使用 Observable 獲取 HttpClient 結果:

我見過很多 Angular 開發人員使用 subscribe 來獲取 Http REST 數據,卻不知道它與 promise 的區別。 subscribe 方法來自 Observable 對象。一旦訂閱,subscribe 回調將在 Observer 產生新數據時執行。而 promise 的 then() 回調處理器最多只能執行一次。因此,除非您需要使用重複數據,否則不要使用 subscribe 。使用 toPromise () 。如果你注意到 Angular 官方文檔中給出的例子; toPromise 有很多用法。

getDataUsingSubscribe() {
this.httpClient.get<Employee>(this.url).subscribe(data => {
this.subscribeResult = data;
console.log(Subscribe executed.)
});
console.log(I will not wait until subscribe is executed..);
}

使用 toPromise 獲取 HttpClient 結果

Rx.js 提供了一個名為 toPromise() 的操作符,可以將 Observeble<T> 轉換成 promise。一旦轉換後,它的 then 塊每當方法產生數據時會被調用執行。

getDataUsingPromise() {
this.httpClient.get<Employee>(this.url).toPromise().then(data => {
this.promiseResult = data;
console.log(Promise resolved.)
});
console.log(I will not wait until promise is resolved..);
}

使用 async-await 獲得 HttpClient 結果:

使用 async-await 模式,我們既不需要 subscribe 也不需要 toPromise 。代碼看起來非常簡單和直接。從 url 獲取數據後,執行第3行,將 Observerable 轉換為 promise,並解析promise,數據存儲在 asyncResult 成員變數中。

async getAsyncData() {
this.asyncResult = await this.httpClient.get<Employee>(this.url).toPromise();
console.log(No issues, I will wait until promise is resolved..);
}

有條件的編程

很多時候,應用程序需要從一個url獲取數據,並根據條件來獲取下一個數據。使用 promise 代碼應該是這樣的:

getConditionalDataUsingPromise() {
this.httpClient.get<Employee>(this.url).toPromise().then(data => {
console.log(First Promise resolved.)
if (data.id > 5) {
let anotherUrl = http://dummy.restapiexample.com/api/v1/employee/23;
this.httpClient.get<Employee>(anotherUrl).toPromise().then(data => {
this.conditionalPromiseResult = data;
console.log(Second Promise resolved.)
});
}
});
}

使用 async-await 代碼是這樣的:

async getConditionalDataUsingAsync() {
let data = await this.httpClient.get<Employee>(this.url).toPromise();
if (data.id > 5) {
let anotherUrl = http://dummy.restapiexample.com/api/v1/employee/23;
this.conditionalAsyncResult = await this.httpClient.get<Employee>(anotherUrl).toPromise();
}
console.log(No issues, I will wait until promise is resolved..);
}

源代碼

你可以從我們的 GitHub 倉庫獲取完整代碼

ultrasonicsoft/ng-async-await-demo?

github.com

總結

總之,async-await 特性為我們在 Angular 應用程序中編寫非同步代碼提供了更好的方法。

參考

  1. ^譯者註:8.0已經完全移除@angular/http
  2. ^已過時

推薦閱讀:

TAG:Angular |