2017-03-27 37 views
2

有了承諾,我們可以使用變體.then在發生錯誤時分割鏈。下面是使用fetch在RxJS中發生錯誤可分割

fetch('http://website.com').then(
    // Perform some logic 
    (response) => response.json().then(({ answer }) => `Your answer: ${answer}`), 
    // Skip json parsing when an error occurs 
    (error) => 'An error occurred :(', 
).then(console.log); 

一個例子這讓我跳過響應處理邏輯,只會在原有取聲明中提出的錯誤迴應。東西RxJS相似可能是這樣的:

Observable.fromPromise(fetch('http://website.com')) 
    // if I put .catch here, the result will be piped into flatMap and map 
    .flatMap(response => response.json()) 
    .map(({ answer }) => `Your answer: ${answer}`) 
    // if I put .catch here, errors thrown in flatMap and map will also be caught 
    .subscribe(console.log); 

如上代碼狀態的評論,我不能簡單地把一個catch運營商,因爲它不具有相同的行爲,我的諾言鏈。

我知道我可以通過自定義操作符來獲得它,包括實現或合併一個錯誤捕捉observable與這個,但這一切似乎是非常重大的矯枉過正。有沒有簡單的方法來實現承諾鏈行爲?

回答

6

其實,如果我在你的情況下,我不會擔心從flatMapmap捕捉錯誤。當源Observable拋出一個錯誤時,它將被傳播給觀察者。所以打電話時我只用一個錯誤處理程序訂閱(否則錯誤被重新拋出):

.subscribe(console.log, err => console.log('error:', err)); 

注意,當在源可觀察(許諾你的情況)出現錯誤,它的傳播爲error通知,而不是標準的next通知。 這意味着flatMap()map()將不會對錯誤消息有任何影響。如果您使用的是catch()materialize(),則兩個運算符(flatMapmap)必須能夠處理此類型的數據(並且不會引發另一個錯誤)。

反正你可以隨時使用share()publish(),使兩種不同的訂閱,每個只處理一種類型的信號:

let source = Observable.fromPromise(fetch('http://website.com')).publish(); 

source 
    .subscribe(undefined, err => console.log(err)); 

source 
    .flatMap(...) 
    .map(...) 
    .subscribe(console.log,() => {}); 

source.connect(); 

現在我只有錯誤的獨立觀察者。

請注意,我必須使用() => {}進行空回調,以免錯誤被忽略。還要注意,當使用多播時(publish()運算符),那麼Subject裏面可能有一些我應該知道的特定行爲,但在你的用例中可能並不重要。

+0

我想區分這兩種錯誤的原因是因爲我可以合理地恢復,或者從'fetch'中的錯誤(例如您的網絡出現問題)提供某種反饋。 如果在flatMap或map中發生錯誤,可能是我自己的錯誤,所以我想讓錯誤傳播給訂閱者。 – Pinpickle

+0

我喜歡你的解決方案,但我的目標是讓結果(在這種情況下,來自錯誤或解析JSON的字符串)成爲相同可觀察部分。你會建議合併這兩個嗎? – Pinpickle

+1

比我可能在'Observable.fromPromise()'後面使用'catch()'並且用我自己的錯誤類('catch()')包裝錯誤,也可以用你自己的錯誤類重新拋出錯誤爲'error信號)。後來在觀察者中,我可以檢查錯誤是typeof還是實現了某個類。這意味着我可以檢查錯誤是否發生在'fromPromise'中,並且被catch()或者來自例如catch。 'map'並且是一個常規錯誤。也許看看'retryWhen()'操作符也會捕獲錯誤,但讓我們根據自己的通知自動重新訂閱... – martin