grustamli
grustamli

Reputation: 466

Concurrent Ajax requests with Rxjs

I'am currently switched from promises to observables. I am using Redux-Observable for my react app. Basically, I am looking for the best operator that will enable mutliple, concurrent ajax calls and return the responses when all the observables have sucessfully finished executing. Here is a code snippet from my app.

let epicPostAd = (action$, store, {ajax}) =>
  action$.ofType(POST_AD)
   .debounceTime(1000)
   .mergeMap(({ payload }) =>
     ajax(generateAjaxRequestSetting(POSTS_URL, 'post', payload,CT_JSON))
      .map(response => postAdSuccessful(response))
      .catch(e => Observable.of(postAdUnsuccessful(e.xhr.response)))
      .takeUntil(action$.ofType(LOCATION_CHANGE))
    )

It is a simple ajax request that posts given ad and dispatches POST_AD_SUCCESSFUL when response is 201 else dispatches POST_AD_UNSUCCESSFUL on error. But the issues is I want to make subsequent ajax observable stream when there is a response. Such as

.map(response => /* start a stream of ajax observables then process the response */)

I will appreciate if you show me the optimal way of achieving this.

Upvotes: 5

Views: 3842

Answers (2)

grustamli
grustamli

Reputation: 466

Here is the answer to my own question. Although JayPhelps answered, I realized that my question was not so clear. Using Jay's recommendation. I came up with the following:

let epicPostAd = (action$, store, {ajax, observable}) =>
  action$.ofType(POST_AD)
   .debounceTime(1000)
   .mergeMap(({ payload }) =>
     ajax(generateAjaxRequestSetting(POSTS_URL, 'post', payload, CT_JSON))
      .mergeMap(response =>
        observable.forkJoin(
          ajax(''),
          ajax('')
        )
      .do(res => {
        const [first, second, third] = results;
        console.log(first, second, third);
      })
      .map(res => postAdSuccessful(res))
    )
    .catch(e => observable.of(postAdUnsuccessful(e.xhr.response)))
    .takeUntil(action$.ofType(LOCATION_CHANGE))

)

So here how it works. I make a post request and immediately after ajax request finishes execution I .mergeMap the response to a stream of ajax ovservables using .forkJoin(). Then process the results

Upvotes: 0

jayphelps
jayphelps

Reputation: 15411

Sounds like you're looking for the forkJoin operator.

It will subscribe to all the Observables you pass to it and after they all complete, it will emit the last value from each inside an array.

It wasn't entirely clear where in your Epic you wanted to do this, so I just made a generic example:

const somethingEpic = (action$, store, { ajax }) =>
  action$.ofType(SOMETHING)
    .mergeMap(() =>
      Observable.forkJoin(
        ajax('/first'),
        ajax('/second'),
        ajax('/third')
      )
      .do(results => {
        // the results is an array, containing each
        const [first, second, third] = results;
        console.log(first, second, third);
      })
      .map(results => ({
        type: 'SOME_RESULTS',
        results
      }))
    );

Technically, it supports a final resultSelector argument you can use instead of using the map operator after it, but I tend not to use it because I've found it's less clear with only negligible performance benefits in common redux-observable style cases. But it's still good to know. Can be handy for more "data-normalization" stuff rather than "transform this into an action" stuff.

const somethingEpic = (action$, store, { ajax }) =>
  action$.ofType(SOMETHING)
    .mergeMap(() =>
      Observable.forkJoin(
        ajax('/first'),
        ajax('/second'),
        ajax('/third'),
        results => ({
          type: 'SOME_RESULTS',
          results
        })
      )
    );

ALSO, if you're asking yourself "what operator do I use?" you should try the operator wizard located in the documentation: http://reactivex.io/rxjs/

Scroll down to the part that says:

Do you need to find an operator for your problem? Start by choosing an option from the list below:

  • I have one existing Observable, and...
  • I have some Observables to combine together as one Observable, and...
  • I have no Observables yet, and...

Hint: open your DevTools to experiment with RxJS.

Though in this case, forkJoin is correctly suggested but when you click on it, it isn't yet documented :sadface: But a google search would present many different websites explaining what it does and how to use it (in RxJS and in other Rx implementations in other languages). Like this helpful website

Upvotes: 10

Related Questions