2017-04-23 9 views
2

サービスコール(実際にはngrx/storeの@Effects)で遅延間隔を長くして再試行パターンを採用しようとしています。私は1コールの作業コードを思いついたので(最適化されていないように見えますが、私の質問ではこれに集中したくはありません)、カスタムObservable演算子にそれを抽出して繰り返し使用したいと思います私のすべてのサービスコールで。最初のカスタムオペレータでrxjs/Observableを正しく拡張する方法

新しい演算子のAPI /使用法を設計する方法と、それをTypeScriptで認識させる方法については空白です。

おそらく、以下のコードはうまくいきません。おそらく、多数の問題が蓄積されているからです。

ので、次のように今私は、コール/効果を持つ:

@Effect() 
    loadData$: Observable<Action> = this.actions$ 
    .ofType(ActionTypes.LOAD_DATA) 
    .pluck('payload') 
    .switchMap(params => { 
     return this.myService.getData(params) 
     .map(res => new LoadDataCompleteAction(res)) 

     // ...and this part would have to be extracted: 
     .retryWhen(attempts => Observable 
      .zip(attempts, Observable.range(1, 5)) 
      .flatMap((n, i) => { 
      if (i < 4) { 
       return Observable.timer(1000 * i); 
      } else { 
       throw(n); 
      } 
      }) 
     ) 
    }) 
    .catch(err => Observable.of(new LoadDataFailed())); 

と私は後にしていますが、他の効果で再試行一部を再利用し、下記のと同様のパターンを持つことができることです。

@Effect() 
    loadData$: Observable<Action> = this.actions$ 
    .ofType(ActionTypes.LOAD_DATA) 
    .pluck('payload') 
    .switchMap(params => { 
     return this.myService.getData(params) 
     .map(res => new LoadDataCompleteAction(res)) 
     .retryWhen(attempts => Observable.retryOrThrow(attempts, maxAttempts) 

     // or maybe - that's my design question 
     .retryOrThrow(attempts, maxAttempts) 
    }) 
    .catch(err => Observable.of(new LoadDataFailed())); 

遅延コールバックパターン(i * 1000)は、アプリケーション全体で一定であると想定できます。

以下のコードは私の試みですが、明らかに機能しません。

declare module 'rxjs/Observable' { 
    interface Observable<T> { 
    retryOrThrow<T>(attempts: any, max: number): Observable<T>; 
    }  
} 

Observable.prototype.retryOrThrow = function(attempt, max) { 
    console.log('retryOrThrow called'); 

    return Observable.create(subscriber => { 
    const source = this; 
    const subscription = source.subscribe(() => { 
     // important: catch errors from user-provided callbacks 
     try { 
      subscriber 
      .zip(attempt, Observable.range(1, max + 1)) 
      .flatMap((n, i) => { 
       console.log(n, i); 
       if (i < max) { 
       return Observable.timer(1000 * i); 
       } else { 
       throw(n); 
       } 
      }); 
     } catch (err) { 
      subscriber.error(err); 
     } 
     }, 
     // be sure to handle errors and completions as appropriate and send them along 
     err => subscriber.error(err), 
    () => subscriber.complete()); 

    // to return now 
    return subscription; 
    }); 
}; 
  1. 私はここで最高の合うだろうか構文、new演算子のためのAPIを設計する方法がわからないです。
  2. 新しい演算子とObservable名前空間またはモジュールを正しく宣言する方法、TypeScriptが新しいものを認識する方法がわかりません。

更新サービスコール:

getMocky(){ 
    const u = Math.random(); 

    const okUrl = 'http://www.mocky.io/v2/58ffadf71100009b17f60044'; 
    const erUrl = 'http://www.mocky.io/v2/58ffae7f110000ba17f60046'; 
    return u > 0.6 ? this.http.get(okUrl) : this.http.get(erUrl); 
    } 

答えて

4

を私はカスタム演算子でrxjsを拡張する方法がわからないので、直接あなたの質問に答えることはできません。

あなたのケースでは、あなた(そして私)は知る必要はありません。 あなたが本当に求めているのは、複数の場所で再利用するために一連の演算子を事前に定義する方法です。

あなたが必要とするのは、let-Operatorです。使用するのは非常に簡単です。

まずあなたは、観察を返す関数に再利用したいロジックを抽出:letを使用して、有効に機能を使用

function retryOrThrow(maxAttempts, timeout) { 
    return (source) => 
    source 
     .retryWhen(attempts => Observable 
     .zip(attempts, Observable.range(1, maxAttempts + 1)) 
     .flatMap((n, i) => { 
      if (i < maxAttempts) { 
      return Observable.timer(timeout * i); 
      } else { 
      throw (n); 
      } 
     }) 
    ); 
} 

を:

@Effect() 
loadData$: Observable<Action> = this.actions$ 
    .ofType(ActionTypes.LOAD_DATA) 
    .pluck('payload') 
    .switchMap(params => { 
    return this.myService.getData(params) 
     .map(res => new LoadDataCompleteAction(res)) 
     // inject the pre-defined logic with the desired parameters 
     .let(retryOrThrow(5, 1000)) 
    }) 
    .catch(err => Observable.of(new LoadDataFailed())); 

letを理解する最も簡単な方法をそれはsource-codeです。ソースオブザーバブルに与えられた関数を適用するだけなので、それは本当にシンプルです。

+0

これはすばらしいことです!どうもありがとうございます!なぜこのページでこの簡単な方法について言及していないのだろうか?https://github.com/ReactiveX/rxjs/blob/master/doc/operator-creationmd – user776686

+0

実際には、このコードに問題があります。メインのエフェクトチェーンにアタッチすると、試行回数は決してリセットされないようです。サービスコールにアタッチされると、実際にはコールは再試行されません。私はケースを分離しようとします。しかし、アイデアごとに - 私はまだ正しい答えを維持しています。 – user776686

+0

switchMapの外ではなくletの直後にキャッチしようとしてください。私はあなたの効果が、letの内側にスローされた後、死にます。 – mtx

関連する問題