bluebirdjs 承诺包裹在 for 循环中
bluebirdjs promises wrapped inside a for loop
我有一堆函数用来为我的服务提供数据。我想遍历它们中的每一个,并在其中一个 returns 获得所需结果时立即停止。如果第一个有效,那很好。如果出现异常或数据无效,我想转到下一个等等。
我怎样才能做到这一点?我有以下代码:
handleData: function(address) {
var self = this;
return new Promise(function (resolve, reject) {
for (var i = 0; i < self.listAllAvailableProviders.length; ++i) {
var handler = self.listAllAvailableProviders[i];
new handler().getData(address)
.then(function(value) {
Logger.info(value);
resolve(value);
})
.catch(function(err){
Logger.error(err);
})
}
reject("");
});
}
如何修复它以便在第一个获得正确数据后立即停止?我已通读 bluebirdjs
文档,但无济于事。
编辑
我在 resolve
之后放了一个 break
语句,我得到了这个:
SyntaxError: Illegal break statement
at Object.exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:513:28)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
如果 promises 不是硬约束 caolan/async#eachSeries 或类似的可能会有帮助。像...
// var Promise = require(?)
// var async = require("async")
handleData: asyncProviderFinder
...
function asyncProviderFinder(address){
var self = this;
return new Promise(function(resolve, reject){
async.eachSeries(
self.listAllAvailableProviders,
function iterate(provider, next){
var handler = provider;
new handler().getData(address)
.then( function(value){
Logger.info(value);
next("abort"); // callback any error to abort future iterations
return resolve(value);
})
.catch( function (err){
Logger.error(err);
next();
});
},
function callback(err, firstProvider){
if ((firstProvider === undefined) && !err ){ reject(""); }
}
);
});
}
您 运行 在 for
循环中并行执行所有请求,因此当您找到一个具有您喜欢的值的请求时,其他请求已经启动,因此无法 "not" 运行 他们。如果您不想 运行 找到其他人,则不需要同时启动它们。因此,这将引导您采用序列化请求的设计模式。 运行一个,不成功,运行下一个,依此类推
据我所知,Bluebird 中没有内置方案来完成您的要求。我能想到的最简单的事情是使用 Bluebird 中的数组处理函数之一,它将一个接一个地序列化请求,例如 Promise.mapSeries()
,然后在找到合适的值时使用拒绝来中止处理。
handleData: function(address) {
return Promise.mapSeries(this.listAllAvailableProviders, function(handler) {
return new handler().getData(address).then(function(value) {
// the first success we get, we will throw with
// the returned value in order to stop the .mapSeries progression
throw value;
}, function(err) {
// log the error, but don't let the rejection propagate so other handlers are called
Logger.error(err);
})
}).then(function() {
// nothing succeeded here, turn it into an overall rejection
throw new Error("No getData() handlers succeeded");
}, function(val) {
// reject here means we got a good value so turn it into a resolved value
return val;
})
}
// usage
obj.handleData().then(function(val) {
// got value here
}).catch(function(err) {
// no values here
});
奇怪的是,如果您自己迭代处理程序,代码似乎会更少,而且可能会更简单:
handleData: function(address) {
var index = 0;
var handlers = this.listAllAvailableProviders;
var handlerCnt = handlers.length;
function next() {
if (index < handlerCnt) {
var handler = handlers[index++];
return new handler().getData(address).catch(next);
} else {
return Promise.reject(new Error("No handler found for address"));
}
}
return next();
}
我有一堆函数用来为我的服务提供数据。我想遍历它们中的每一个,并在其中一个 returns 获得所需结果时立即停止。如果第一个有效,那很好。如果出现异常或数据无效,我想转到下一个等等。
我怎样才能做到这一点?我有以下代码:
handleData: function(address) {
var self = this;
return new Promise(function (resolve, reject) {
for (var i = 0; i < self.listAllAvailableProviders.length; ++i) {
var handler = self.listAllAvailableProviders[i];
new handler().getData(address)
.then(function(value) {
Logger.info(value);
resolve(value);
})
.catch(function(err){
Logger.error(err);
})
}
reject("");
});
}
如何修复它以便在第一个获得正确数据后立即停止?我已通读 bluebirdjs
文档,但无济于事。
编辑
我在 resolve
之后放了一个 break
语句,我得到了这个:
SyntaxError: Illegal break statement
at Object.exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:513:28)
at Object.Module._extensions..js (module.js:550:10)
at Module.load (module.js:458:32)
at tryModuleLoad (module.js:417:12)
at Function.Module._load (module.js:409:3)
at Module.require (module.js:468:17)
at require (internal/module.js:20:19)
如果 promises 不是硬约束 caolan/async#eachSeries 或类似的可能会有帮助。像...
// var Promise = require(?)
// var async = require("async")
handleData: asyncProviderFinder
...
function asyncProviderFinder(address){
var self = this;
return new Promise(function(resolve, reject){
async.eachSeries(
self.listAllAvailableProviders,
function iterate(provider, next){
var handler = provider;
new handler().getData(address)
.then( function(value){
Logger.info(value);
next("abort"); // callback any error to abort future iterations
return resolve(value);
})
.catch( function (err){
Logger.error(err);
next();
});
},
function callback(err, firstProvider){
if ((firstProvider === undefined) && !err ){ reject(""); }
}
);
});
}
您 运行 在 for
循环中并行执行所有请求,因此当您找到一个具有您喜欢的值的请求时,其他请求已经启动,因此无法 "not" 运行 他们。如果您不想 运行 找到其他人,则不需要同时启动它们。因此,这将引导您采用序列化请求的设计模式。 运行一个,不成功,运行下一个,依此类推
据我所知,Bluebird 中没有内置方案来完成您的要求。我能想到的最简单的事情是使用 Bluebird 中的数组处理函数之一,它将一个接一个地序列化请求,例如 Promise.mapSeries()
,然后在找到合适的值时使用拒绝来中止处理。
handleData: function(address) {
return Promise.mapSeries(this.listAllAvailableProviders, function(handler) {
return new handler().getData(address).then(function(value) {
// the first success we get, we will throw with
// the returned value in order to stop the .mapSeries progression
throw value;
}, function(err) {
// log the error, but don't let the rejection propagate so other handlers are called
Logger.error(err);
})
}).then(function() {
// nothing succeeded here, turn it into an overall rejection
throw new Error("No getData() handlers succeeded");
}, function(val) {
// reject here means we got a good value so turn it into a resolved value
return val;
})
}
// usage
obj.handleData().then(function(val) {
// got value here
}).catch(function(err) {
// no values here
});
奇怪的是,如果您自己迭代处理程序,代码似乎会更少,而且可能会更简单:
handleData: function(address) {
var index = 0;
var handlers = this.listAllAvailableProviders;
var handlerCnt = handlers.length;
function next() {
if (index < handlerCnt) {
var handler = handlers[index++];
return new handler().getData(address).catch(next);
} else {
return Promise.reject(new Error("No handler found for address"));
}
}
return next();
}