Mudd
Mudd

Reputation: 107

Redux-Observable - Dispatch multiple actions that have to be run in sequence

Using redux-observable, I'm trying to spawn off multiple WORK actions from a single epic, like so:

( action$, state$ ) => {
   return action$.pipe(
      ofType( 'SPAWN' ),
      flatMap( action => {
         return [
            { type: 'WORK', payload: 'a' },
            { type: 'WORK', payload: 'b' },
            { type: 'WORK', payload: 'c' },
         ];
      } )
   )
}

The actions are firing off fine, but problem is, these WORK actions are async and thus they are handled by another epic, like so:

( action$, state$ ) => {
   return action$.pipe(
      ofType( 'WORK' ),
      flatMap( action => {
         const promise = new Promise( resolve => {
            setTimeout( () => {
               resolve( { type: 'SET', payload: action.payload } );
            }, Math.random() * 5000 ); // promise may resolve at different times
         } );

         return promise;
      } )
   )
}

At the reducer for action SET, I would expect, the sequence to be in order, regardless of the randomness of the setTimeout above, since the flatMap is returning promises. The result should be like so:

a
b
c

Nonetheless, I'm getting random orderings for the SET action, for example:

b
c
a

Would really appreciate it if anyone can point me to the right direction and aid me in my understanding.

Working Update As per the answer from @Oles Savluk, I've edited the WORK epic to be as follows:

( action$, state$ ) => {
   return action$.pipe(
      ofType( 'WORK' ),
      concatMap( action => {
         const promise = new Promise( resolve => {
            setTimeout( () => {
               resolve( { type: 'SET', payload: action.payload } );
            }, Math.random() * 5000 ); // promise may resolve at different times
         } );

         return promise;
      } )
   )
}

Notice that the use of concatMap makes actions of the type WORK to be arranged in the stream sequentially. One action waits for another to complete before executing.

Upvotes: 2

Views: 3087

Answers (2)

Oles Savluk
Oles Savluk

Reputation: 4345

You need to use concatMap operator which will emit items sequentially instead of flatMap(mergeMap) which do this concurrently

If you are new to Rx you can read this article to understand the difference between flattening operators.

Upvotes: 2

ggradnig
ggradnig

Reputation: 14199

With flatMap, all emissions of the inner observable are forwarded to the outer observable in order of their occurance. Now, with a Promise, that emission is created only when the Promise resolves, not immediately. Therefore, you receive the "random" order that is created by the timeout.

Upvotes: 1

Related Questions