[翻譯]在 Angular 中使用 async-await 特性
在 Angular 中使用 async-await 特性
原文鏈接:
https://medium.com/@balramchavan/using-async-await-feature-in-angular-587dd56fdc77更新:在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總結
總之,async-await
特性為我們在 Angular 應用程序中編寫非同步代碼提供了更好的方法。
參考
- ^譯者註:8.0已經完全移除@angular/http
- ^已過時
推薦閱讀:
TAG:Angular |