[英]How to execute promises in series?
var promiseReturningFuncs = [];
for(var i = 0; i < 5; i++){
promiseReturningFuncs.push(askQuestion);
}
var programmers = [];
Promise.reduce(promiseReturningFuncs, function(resp, x) {
console.log(typeof resp);
if(typeof resp != "function") {
programmers.push(resp);
}
return x();
})
.then(function(resp) {
programmers.push(resp);
console.log(programmers);
});
我的目标:依次执行askQuestion函数并解析该函数创建的对象数组。 (此功能必须按顺序执行,以便可以响应用户输入)
想象一下,askQuestion函数返回一个可以解析我要添加到数组中的对象的promise。
这是我的杂乱方式。 我正在寻找找到一种更清洁的方法,理想情况下,我什至不需要推送到数组,而只有一个最终的.then,其中响应是一个数组。
由于您似乎正在使用Bluebird Promise库,因此有许多内置选项可用于对Promise返回函数进行排序。 您可以使用Promise.reduce()
, Promise.map()
并发值为1, Promise.mapSeries
或Promise.each()
。 如果迭代器函数返回了一个Promise,则所有这些都将等待下一次迭代,直到该Promise得以解决。 使用哪种方法更多地取决于数据的结构方式和所需的结果(实际上都不显示或描述的结果)。
假设您有一系列的promise返回函数,并且想一次调用它们,等待一个函数解析后再调用下一个。 如果您想要所有结果,那么我建议Promise.mapSeries()
:
let arrayOfPromiseReturningFunctions = [...];
// call all the promise returning functions in the array, one at a time
// wait for one to resolve before calling the next
Promise.mapSeries(arrayOfPromiseReturningFunctions, function(fn) {
return fn();
}).then(function(results) {
// results is an array of resolved results from all the promises
}).catch(function(err) {
// process error here
});
也可以使用Promise.reduce()
,但它会累加一个结果,将结果从一个传递到下一个,并以一个最终结果结束(就像Array.prototype.reduce()
一样)。
Promise.map()
是一个更普遍的版本Promise.mapSeries()
可以让你控制并发数(在飞行异步操作的同时数)。
Promise.each()
还将对您的函数进行排序,但不会累加结果。 它假定您没有结果,或者您正在带外或通过副作用累积结果。 我倾向于不喜欢使用Promise.each()
因为我不喜欢副作用编程。
您可以使用ES6(ES2015)功能在纯JS中解决此问题:
function processArray(arr, fn) {
return arr.reduce(
(p, v) => p.then((a) => fn(v).then(r => a.concat([r]))),
Promise.resolve([])
);
}
它将给定数组的函数应用于序列,并解析为结果数组 。
用法:
const numbers = [0, 4, 20, 100];
const multiplyBy3 = (x) => new Promise(res => res(x * 3));
// Prints [ 0, 12, 60, 300 ]
processArray(numbers, multiplyBy3).then(console.log);
您将要仔细检查浏览器的兼容性,但这适用于相当当前的Chrome(v59),NodeJS(v8.1.2)以及大多数其他浏览器。
使用递归函数(以非承诺方式)一个接一个地执行:
(function iterate(i,result,callback){
if( i>5 ) callback(result);askQuestion().then(res=>iterate(i+1,result.concat([res]),callback);
})(0,[],console.log);
出于保证,可以将其包装在承诺中:
function askFive(){
return new Promise(function(callback){
(function iterate(i,result){
if( i>5 ) callback(result);askQuestion().then(res=>iterate(i+1,result.concat([res]),callback);
})(0,[],console.log);
});
}
askFive().then(console.log);
要么:
function afteranother(i,promise){
return new Promise(function(resolve){
if(!i) return resolve([]);
afteranother(i-1,promise).then(val=>promise().then(val2=>resolve(val.concat([val2])));
});
}
afteranother(5,askQuestion).then(console.log);
您可以使用递归,以便可以在then
块中移至下一个迭代。
function promiseToExecuteAllInOrder(promiseReturningFunctions /* array of functions */) {
var resolvedValues = [];
return new Promise(function(resolve, reject) {
function executeNextFunction() {
var nextFunction = promiseReturningFunctions.pop();
if(nextFunction) {
nextFunction().then(function(result) {
resolvedValues.push(result);
executeNextFunction();
});
} else {
resolve(resolvedValues);
}
}
executeNextFunction();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.