Search code examples
javascriptpromisebluebird

Process an array of API calls sequentially with Bluebird.mapSeries


What I've been trying is to process API calls sequentially, which are pushed into an array.

function resolveApi(callback) {
  return new Promise(function(resolve, reject) { resolve(callback) });
}

function callApi(){

    var promises = [];
    promises.push(resolveApi(Restangular.one("api/blahblah",{/*input data*/})));
    promises.push(resolveApi(Restangular.one("api/another/api",{/*input data*/})));
    //there are other similar API calls.
    //Restangular is supposed to return an API call

    promises = Bluebird.mapSeries(promises, function(item, index) {
        return item;     
    });

    promises.then(function(){/* the end */});
}

The goal is to process each of the API calls in promises array, but the code above doesn't do this. (i.e. API calls are called almost simultaneously, while each API call is supposed to wait until the previous one is done.)

Do you see anything I'm doing wrong?

Any advice will be appreciated.


Solution

  • OK, if Restangular.one() returns a promise (which your comment now indicates) and you want to process these api calls sequentially (one after the other), then you just have to organize the arguments to Bluebird's .mapSeries() correctly. It takes an array of data and a function (that operates on that data and returns a promise).

    So, let's organize your stuff that way:

    const data = [
        {endPoint: "http://somedomain.com/api/blahblah", args: [1,2]},
        {endPoint: "http://somedomain.com/api/another/api", args: ["a", "b"]},
        {endPoint: "http://somedomain.com/api/yetanother", args: ["abc"]},
    ];
    
    Promise.mapSeries(data, function(dataObj) {
        return Restangular.one(dataObj.endPoint, ...dataObj.args);
    }).then(results => {
        // array of results here
        console.log(results);
    }).catch(err => {
        // error occurred here
        console.log(err);
    });
    

    Since you said that Restangular.one() already returns a promise, I don't see any reason why you need to wrap it in your resolveApi() function. That isn't needed and we certainly don't need to turn a promise into a plain callback to use .mapSeries().


    There were lots of things missing in your implementation, but the main one was that you were calling all the asynchronous operations immediately and then trying to manage the promises. That will not sequence your operations. That runs them all in parallel. Further if you give .mapSeries() an array of promises, it can't sequence the operations because they've all already been started. To let it manage when the asynchronous operations are started so that it can sequence them, you have to pass it an array of data and a function to call that is passed an item of that data and will return a promise. Then, it can call them one at a time and your operations will get started one at a time.