我正在寻求建筑建议。在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);
}
}
现在我不知道如何确保:
- 并发地(而不是顺序地)触发所有请求响应时间)
- 一旦我得到所有API请求的响应,就响应客户端
- 如果一个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);
});
}