简体   繁体   中英

Javascript BlueBird Promises: architecture for concurrent API requests

I am seeking for an architecture advice. Using Bluebird Promises in a MEAN environment (talking node.js server-side here), I intend to make many concurrent API calls, aggregate all results and respond to client. Example (pseudo-)code:

exports.getAllData = function(searchquery, cb) {
    var results; 

   wrapper1.getResultsFromAPI1(searchquery, function(err,data){
    results += data;
   });

   wrapper2.getResultsFromAPI2(searchquery, function(err,data){
       results += data;
   });

   wrapper3.getResultsFromDataBase(searchquery, function(err,data){
       results += data;
   });

   if (AllRequests done){
       cb(null,results);
   }
}

Now I don't know how I can make sure to:

  1. Fire all requests concurrently (NOT sequentially to reduce response time)
  2. Respond to client once I got responses from ALL API requests
  3. In case of one API request to fail for whatever reason, not having the entire promise chain to be rejected, thus "loosing" the other API response data.

I checked on Bluebird Promise website for appropriate collections, but none seems to fully meet the requirements listed above. Any suggestions?

One way of doing this would be using reflect calls.

var Promise= require('bluebird');

Promise.props({
  "wrapper1": someasync(1).reflect(),
  "wrapper2": someasync(0).reflect(),
  "wrapper3": someasync(1).reflect()
})
.then(function(results) {
  Object.keys(results).forEach(function(key) {
    if (results[key].isRejected()) {
      console.log(key + " failed.", results[key].reason());
    } else {
      console.log(key + " successed", results[key].value());
    }
  });
});

function someasync(t) {
  if (t===0) return Promise.reject('some err');
  else return Promise.resolve(true);
}

Which results in the following:

wrapper1 successed true
wrapper2 failed. some err
wrapper3 successed true
var Promise= require('bluebird');
var chain = require('lodash').chain;

function rejectedPromise(settledPromise) {
    return settledPromise.isRejected(); 
}

function extractResponse(fulfilledPromise) {
    return fulfilledPromise.value();
}

Promise.settle([
    asyncCall(),  
    asyncCall(),  
    asyncCall() 
])
.then(function retrieveSuccessfulResponses(settledPromises) {
    return chain(settledPromises)
        .reject(rejectedPromise)  
        .map(extractResponse)
});

If you want, you can manually promisify your API methods, eg:

var p1 = new Promise(function(resolve, reject) {
  wrapper1.getResultsFromAPI1(searchquery, function(err, data) {
    if (err) reject(err);
    else resove(data);
  });
});

But since you're using the BlueBird library, then you can use Promise.promisify , so you can avoid the boilerplate code of wrapping the methods into promises. Eg:

var getResultsFromAPI = Promise.promisify(wrapper1.getResultsFromAPI1);
var p1 = getResultsFromAPI(searchquery);

And if you want to promisify all the methods of an API, you can use Promise.promisifyAll . Eg:

var wrapper1 = Promise.promisifyAll(require('my-api'));

// then, all the wrapper1 methods are already wrapped into a Promise
var p1 = wrapper1.getResultsFromAPI1(searchquery);

So, after turning all your methods into Promises, you can use the Promise.settle to achieve what you want: See what promises were fulfilled and what of them were rejected:

exports.getAllData = function(searchquery, cb) {
  /* Don't forget to promisify all the API methods firstly */

  var results;

  var p1 = wrapper1.getResultsFromAPI1(searchquery);
  var p2 = wrapper2.getResultsFromAPI2(searchquery);
  var p3 = wrapper3.getResultsFromDataBase(searchquery);

  Promise.settle([p1, p2, p3]).then(function(arr) {
    arr.forEach(function(res, index) {
      if (res.isFulfilled()) {     // check if the Promise was fulfilled
        results += res.value();    // the Promise's return value
      }
      else if (res.isRejected()) { // check if the Promise was rejected
        console.log(res.reason()); // do something with the error
      }
    });

    cb(null, results);
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM