angular2 學習筆記 ( Rxjs, Promise, Async/Await 的區別 )


更新 2019-07-17 

function abc(): Promise<string>{
  return new Promise(resolve => {
     resolve('dada');
     console.log('yeah')
  });
}

resolve 之后你再調用 resolve 外部是不會理會的, 這和 .next 不同

另外 resolve 也不等於 return;

resolve 之后的代碼依然會執行.

 

 

Promise 是 ES 6

Async/Await 是 ES 7

Rxjs 是一個 js 庫

在使用 angular 時,你會經常看見這 3 個東西.

它們都和異步編程有關,有些情況下你會覺得用它們其中任何一個效果都一樣. 但又覺得好像哪里不太對....

這篇就來說說,我在開發時的應用方式.

在 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 事件. 

 





 


免責聲明!

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



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