2016-11-08 10 views
2

私は、デバイスを複数回照会する必要があります。すべてのクエリは非同期である必要があり、デバイスは一度に同時クエリをサポートしません。それが照会されると また、それは直後に再度照会することができません。正常に動作するには、少なくとも1秒の休止が必要です。なぜ完全な連結を実行した後に呼び出されていませんか?

saveClock()saveConfig()によって実行される2つのクエリは、Promiseを返し、両方とも期待どおりに未定義を返して解決します。 take()を削除するとからtoArray()を防ぎ、なぜ次のコードで

が呼ばれていますか?ここで何が起こっている
、同じ動作を達成するためのより良い方法はありますか?

export const saveEpic = (action$, store) => 
    action$.ofType(SAVE) 
    .map(action => { 
     // access store and create object data 
     // ... 
     return data; 
    }) 
    .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)), 
     Rx.Observable.of(data.id) 
    ]) 
    ) 
    .concatAll() 
    .take(4) 
    .toArray() 
    // [undefined, 0, undefined, "id"] 
    .map(x => { type: COMPLETED, id: x[3] }); 
+1

なぜ 'take()'を削除すると 'toArray()'が呼び出されないのですか?まあ、いつこの観測が完了したのですか? 'toArray()'は完了したオブザーバブルでのみ機能し、不完全なストリームの値を返すことはできません。したがって、ストリームに固有の終端がない場合(つまり、イベントリスナーなどに結び付けられている場合)、 'toArray'は決して呼び出されません。しかし、 'take()'は、4つの項目が出力されたときにストリームを「完全」にします。 – aaronofleonard

答えて

2

私が見るカップルの事があります。

あなたの最終.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回以上送信されないという叙事詩がある場合は、すべての叙事詩のためにこれを保証する単一監督者の。

これはすべて非常に複雑に見えるかもしれませんが、おそらく皮肉なことに、これは従来の命令コードよりもがの方が扱いやすいように、です。最も難しいのは実際にパターンを知ることです。

+0

括弧については申し訳ありませんが、質問コードに間違いがあります。しかし、多額の節約についての問題を指摘してくれてありがとう。私は長命の叙事詩については考えていませんでしたが、ユーザーが複数の 'SAVE'アクションをディスパッチするのを防ぎました。 'SAVE'アクションがディスパッチされると、UIは' COMPLETE'アクションがディスパッチされるまで再び保存を許可しません。それにもかかわらず、私は背圧の仕組みが非常に興味深く、二重チェックが本当に便利だと思っています。幸いにも、私はデバイスを照会する他の叙事詩を持っていないので、私はそれを防ぐためにどんなメカニックも必要ありません。 –

+0

叙事詩を生かし続けることは、私の問題を解決したようです。ありがとうございました! –

+0

あなたは大歓迎です! – jayphelps

関連する問題