更新 2019-07-17 java
function abc(): Promise<string>{ return new Promise(resolve => { resolve('dada'); console.log('yeah') }); }
resolve 以後你再調用 resolve 外部是不會理會的, 這和 .next 不一樣ajax
另外 resolve 也不等於 return;編程
resolve 以後的代碼依然會執行.c#
Promise 是 ES 6promise
Async/Await 是 ES 7異步
Rxjs 是一個 js 庫async
在使用 angular 時,你會常常看見這 3 個東西.異步編程
它們都和異步編程有關,有些狀況下你會以爲用它們其中任何一個效果都同樣. 但又以爲好像哪裏不太對....this
這篇就來講說,我在開發時的應用方式.url
在 Typescript 尚未支持 Async/Await 的時候, angular 就已經發布了.
那時咱們只想着 Promise vs Rxjs
這 2 者其實很好選擇, 由於 "可讀性" 和 "代碼量" 是差不錯的.
而 Rxjs 有一些 Promise 沒有的特性.
好比一堆的 operator, 這讓咱們很方便的操做 stream, 這是 Promise 沒有的. (能夠去看看如何用 rxjs 來實現 search text, triple click 等等, 幾行代碼就能夠完成了)
此外 Rxjs 能夠持續的監聽和響應, 這點也是 Promise 作不到的.
因此絕大部分狀況下,咱們鼓勵開發者使用 Rxjs.
而在 angular 自帶的多種方法中,默認返回的也都是 Rxjs.
結論是 :
a.若是要持續監聽和響應或則要用 operator 那麼必定是選 Rxjs
b.其它狀況就對比 2 者的 "可讀性" 和 "代碼量" (在沒有 Async/Await 的年代, 它們是同樣的), 因此仍是選 Rxjs 就對了.
後來, Typescript 支持了 Async/Await
這讓狀況發生了變化.
Async/Await 的 "可讀性" 是比 Promise 要好的 (代碼越複雜,可讀性就越好)
因此剛剛的結論 a 依然沒有改變
可是結論 b 就有了變數.
下面咱們來看看對比的代碼
咱們說 Async/Await 可讀性高是指 "它的返回方式和咱們寫同步代碼很類似"
let a = getData(); // 同步代碼 let a = await getDataAsync(); // Async/Await 代碼
這是它好讀的緣由.
可是呢.. 當咱們加上錯誤處理時,它也許就沒有那麼好了.
async click() { try { let a = await getDataAsync(); } catch(e) { // handle error } }
Async/Await 是用 catch 來捕獲的.
這和 java, c# 相似, 讀起來還算能夠, 可是若是你有多個異步代碼, 並且要不一樣的錯誤處理呢 ?
async click() { try { let a = await this.http.get('urlA'); let b = await this.http.get('urlB'); let c = await this.http.get('urlC'); } catch(e) { // 咱們須要在這裏識別出不一樣的 error 作不一樣的處理 } }
把成功和失敗的邏輯分開, 並不會讓代碼更好讀, 並且還須要寫識別錯誤的邏輯...
因此咱們能夠這樣寫
async click() { try { let a = await this.http.get('urlA').catch(e => { this.errorMessage = 'A failed'; throw ''; }); let b = await this.http.get('urlB').catch(e => { this.errorMessage = 'B failed'; }); let c = await this.http.get('urlC'); } catch(e) { // 什麼都不處理 } }
勉強還行... 可是爲何 .catch 裏面還須要 throw 呢 ? 爲何有一個 "什麼都不處理呢" ?
這是由於
let a = await this.http.get('urlA').catch(e => { this.errorMessage = 'A failed'; // 假設沒有 throw, let a 會是 undefined, let b, let c 會繼續執行... // 假設 return whatever, let b, let c 也會執行. // 你要中斷 let b, let c 只有 2 個方法. // 1. throw ''; // 2. Promise.reject(''); // 這是 Async/Await 和 Promise 不一樣的地方 });
一旦你 throw 了, 外面就要有人 catch 否則就會 throw 到 angular 的 catch 裏頭了 (注意個人 click 是 component 的方法).
因此就有了一個
catch(e) { // 什麼都不處理, 實際上是爲了防止 throw 到 angular 的 catch 裏頭 /.\ }
寫 Promise 是不須要 try catch 的,由於 Promise 一旦進入 reject 就不可能進入下一個 then 了, 而 Async/Await 須要配搭 try catch throw.
結論 :
a.若是要持續監聽和響應或則要用 operator 那麼必定是選 Rxjs
b.其他狀況就看我的了
-看慣了 Promise, 又看不慣 try catch 的話建議用 Promise 就行了.
-但若是 2 種方式你都看的習慣, 那麼建議寫 Async/Await 吧
由於看不慣 Promise 的人, 你寫 Promise, 他就死了.
但是看不慣 try catch 的人, 你寫 try catch, 他還死不了.
另外,
Rxjs 有一個 toPromise 的功能, 這有時候讓人很困惑的...
要知道 Rxjs.toPromise() 只有在 rxjs.complete 時纔會觸發.
也就是說若是一個 rxjs 它須要持續監聽, 那麼你用 toPromise 就會毀了. 必定要用 subscribe
angular 的 http 發了 ajax 後就會 complete 了, 因此你可使用 toPromise, 可是 ActivatedRoute.paramMap 你 toPromise 就完蛋了, 它不會 complete 因此也就不會觸發你的 promise 事件.