私が見るカップルの事があります。
あなたの最終.map()
は、現在の形で構文エラーで括弧を、不足していますが、微妙な変更は偶然labeled statementの代わりに、オブジェクトを返す作ることができます。現在のフォームでは構文エラーですので、これはあなたのコード(実行されないでしょう)ではなく、このポストのバグだと思いますが、二重チェック!固定それと
// before
.map(x => { type: COMPLETED, id: x[3] });
// after
.map(x => ({ type: COMPLETED, id: x[3] }));
、例は、単純なReduxの、観察可能なテストケースを実行しない:私は違ったあなたよりもやった注目に値する何もないのであれば、問題が設けられていないコードにあるようにを思わhttp://jsbin.com/hunale/edit?js,output。 、追加的な洞察や、より良いを追加するにはお気軽に私たちのためにJSBin/Gitのレポでそれを再現します。あなたが言及したが、非常に非常に注目すべきではなかった
ことの一つは、Reduxの-観測可能で、あなたの叙事詩は、一般的に長寿命の「プロセス管理」になるということです。この叙事詩は、実際にはこれらの保存のうちの1つを処理し、次にcomplete()を実行しますが、これはおそらくあなたが実際に望むものではありません。ユーザーはアプリケーションの起動ごとに何かを保存することはできますか?おそらくないだろう。
代わりに、mergeMap
の内部にこのロジックをカプセル化することで、叙事詩が生き生きとしたトップレベルのストリームを生き生きとし、今後の行動を聞きたがっているといいでしょう。 take(4)
とdata.id
はその後、余分になっ渡し:
const saveEpic = (action$, store) =>
action$.ofType(SAVE)
.mergeMap(data =>
Rx.Observable.from([
Rx.Observable.of(data).mergeMap(data => saveClock(data.id, data.clock)),
Rx.Observable.timer(1000),
Rx.Observable.of(data).mergeMap(data => saveConfig(data.id, data.config))
])
.concatAll()
.toArray()
.map(() => ({ type: COMPLETED, id: data.id }))
);
ストリームのこの分離は、エラーのコンテキストで、彼の最近のAngularConnect会談でベン・レッシュによって記述されているが、それはまだ適用です:https://youtu.be/3LKMwkuK0ZE?t=20m(心配しないで、この!アンギュラ特有の問題ではありません)
は次に、私はあなたの人生を容易にするかもしれないいくつかの迷惑リファクタリングのアドバイスを共有したいと思ったが、確かにこれはとても無視して自由に感じる独断さ:
私はより正確に反映するためにリファクタリングしますイベントの視覚的順序、および複雑さを軽減:
const saveEpic = (action$, store) =>
action$.ofType(SAVE)
.mergeMap(data =>
Rx.Observable.from(saveClock(data.id, data.clock))
.delay(1000)
.mergeMap(() => saveConfig(data.id, data.config))
.map(() => ({ type: COMPLETED, id: data.id }))
);
ここでは、約束を消費している、それはまた、消費される約束を返しsaveConfig()
への呼び出しに結果をmergeMapping、1000msのための出力だ遅らせ、saveClock
によって返されました。最後にその結果をCOMPLETE
アクションにマッピングします。他のものは機内残っているかいないが、複数のSAVE要求を受けたから、それを停止し、そのまま
最後に、あなたのエピックがが生き続けるんし、長く住んでいた場合は、何もこの叙事詩ではありませんことを覚えておいてください要求間で要求される1000msの遅延を使い果たしてしまった。すなわち、の間の1000msのスペースが実際に要求されている場合、あなたの叙事詩そのものはあなたのUIコードがそれを壊さないように完全には防御しません。その場合は、より複雑なバッファ付きのbackpressureメカニズムを追加することを検討してください。たとえば、.zip()
演算子をBehaviorSubject
とします。
http://jsbin.com/waqipol/edit?js,output
const saveEpic = (action$, store) => {
// used to control how many we want to take,
// the rest will be buffered by .zip()
const requestCount$ = new Rx.BehaviorSubject(1)
.mergeMap(count => new Array(count));
return action$.ofType(SAVE)
.zip(requestCount$, action => action)
.mergeMap(data =>
Rx.Observable.from(saveClock(data.id, data.clock))
.delay(1000)
.mergeMap(() => saveConfig(data.id, data.config))
.map(() => ({ type: COMPLETED, id: data.id }))
// we're ready to take the next one, when available
.do(() => requestCount$.next(1))
);
};
我々はまだ既存のものがバッファリングされた処理をしている、と我々は唯一の時間でそれらのいずれかを実行しながら、それを保存するためのリクエストが来るように、これはそれを作ります。ただし、これは無制限のバッファであることに注意してください。つまり、保留中のアクションのキューは、バッファがフラッシュされるよりも無限に速く成長する可能性があります。重複したリクエストを破棄するなど、ロスの背圧のための戦略を採用しない限り、これは避けられません。
要求が重複して1秒に1回以上送信されないという叙事詩がある場合は、すべての叙事詩のためにこれを保証する単一監督者の。
これはすべて非常に複雑に見えるかもしれませんが、おそらく皮肉なことに、これは従来の命令コードよりもがの方が扱いやすいように、です。最も難しいのは実際にパターンを知ることです。
なぜ 'take()'を削除すると 'toArray()'が呼び出されないのですか?まあ、いつこの観測が完了したのですか? 'toArray()'は完了したオブザーバブルでのみ機能し、不完全なストリームの値を返すことはできません。したがって、ストリームに固有の終端がない場合(つまり、イベントリスナーなどに結び付けられている場合)、 'toArray'は決して呼び出されません。しかし、 'take()'は、4つの項目が出力されたときにストリームを「完全」にします。 – aaronofleonard