Javascript BlueBird Promises:并发API请求的架构



我正在寻求建筑建议。在MEAN环境中使用Bluebird Promises(这里谈论node.js服务器端),我打算进行许多并发API调用,汇总所有结果并响应客户端。例子(伪)代码:

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);
   }
}

现在我不知道如何确保:

    并发地(而不是顺序地)触发所有请求响应时间)
  1. 一旦我得到所有API请求的响应,就响应客户端
  2. 如果一个API请求由于任何原因失败,没有整个承诺链被拒绝,从而"丢失"其他API响应数据。

我在蓝鸟承诺网站上查看了合适的集合,但似乎没有一个完全符合上面列出的要求。有什么建议吗?

一种方法是使用reflect调用。

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);
}

结果如下:

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)
});

如果你愿意,你可以手动承诺你的API方法,例如:

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

但是由于您使用的是BlueBird库,那么您可以使用Promise.promisify,这样您就可以避免将方法包装成承诺的样板代码。例句:

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

如果你想保证一个API的所有方法,你可以使用Promise.promisifyAll。例句:

var wrapper1 = Promise.promisifyAll(require('my-api'));
// then, all the wrapper1 methods are already wrapped into a Promise
var p1 = wrapper1.getResultsFromAPI1(searchquery);

所以,在把你所有的方法都变成承诺之后,你可以使用Promise.settle来实现你想要的:看看哪些承诺被实现了,哪些被拒绝了:

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);
  });
}

最新更新