为什么这个map reduce Promises数组不起作用,而只是减少它起作用
why this map reduce Promises array does not work, but just reducing it does?
假设您有一个异步进程,它是n个异步步骤的级联:
function step1(item){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('step 1 fort item ' + item);
});
});
}
function step2(item){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('step 2 for item ' + item);
},1000);
});
}
function step3(item){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('step 3 for item ' + item);
},1000);
});
}
function processItem(item){
let steps = [step1, step2, step3];
return steps.reduce((current, next) => {
return current.then(res => {
console.log(res);
return next(item);
}).then(res => {
console.log(res);
});
},Promise.resolve());
}
因此,现在您有了一个items数组,并且您希望处理所有项,并将函数processItem应用于每个项。但由于限制,所有进程都必须按顺序执行,一个进程在前一个进程完成时开始。
好吧,如果我用这种方式实现它:
let items = [1, 2, 3];
items.map(i => processItem(i)).reduce((p, next) => {
return p.then(() => {
return next;
});
}).then(() => {
// all finished
});
你会得到这样的输出:
step 1 for item 1
step 1 for item 2
step 1 for item 3
step 2 for item 1
step 2 for item 2
step 2 for item 3
step 3 for item 1
step 3 for item 2
step 3 for item 3
并且只需要3秒,而不是预期的9秒。
同时,如果你避免地图步骤来实现它,你会得到预期的结果:
let items = [1, 2, 3];
items.reduce((promise, nextItem) => {
return promise.then(() => {
return processItem(nextItem);
});
}, Promise.resolve()).then(() => {
// all finished
});
结果:
step 1 for item 1
step 2 for item 1
step 3 for item 1
step 1 for item 2
step 2 for item 2
step 3 for item 2
step 1 for item 3
step 2 for item 3
step 3 for item 3
并且需要预期的9秒。
为什么会发生这种情况?我认为,当你将一个promise返回函数映射到一个数组时,你会得到一个promises数组,所以reduce匿名函数的第一个和第二个参数就是promise,你可以像我在上面第一个例子中所做的那样。我对此有点困惑。
.map
正在调用传递给它的函数,如果您不希望在这一步调用processItem
,则需要再次包装它,即
let items = [1, 2, 3];
items.map(i => () => processItem(i)).reduce(
(p, next) => p.then(next),
Promise.resolve()
).then(() => {
// all finished
});
谢谢@Paul S.
以你的答案为基础,我想我更喜欢包装原始的processItem
函数:
function processItem(item){
return function(){
let steps = [step1, step2, step3];
return steps.reduce((current, next) => {
return current.then(res => {
console.log(res);
return next(item);
}).then(res => {
console.log(res);
});
},Promise.resolve());
}
}
然后地图会变得更干净:
items = [1, 2, 3];
items.map(i => processItem(i)).reduce((p, next) => {
return p.then(() => {
return next();
});
}, Promise.resolve()).then(() => {
// all finished
});
相关文章:
- electronic BrowserWindow的最小高度和宽度在hide()show()方法之后不起作用
- 监视函数从服务返回不起作用,但作用域函数起作用
- 幻灯片滚动javascript不起作用
- 简单的javascript在Shopify中不起作用
- Recaptcha在IE7和IE8中不起作用
- Ember Data DS.Model's set函数不起作用
- JsFiddle上的鼠标事件不起作用
- 我的AngularJS表达式没有'不起作用
- 点击按钮输入不起作用
- 面向对象的Javascript代码在IE7中不起作用
- 分部隐藏在jquery中不起作用
- 在phonegap应用程序内部重定向不起作用
- Array.length似乎不起作用;console.log则显示其他情况
- $ionicplatform内的$scope不;不起作用
- 我的javascript for循环不起作用
- Meteor-添加用户自定义字段的方法不起作用
- 为什么 .focus() 不起作用,而 .css(“color”,“red”) 在同一个选择器上起作用
- Textarea必需的attribut在javascript中不起作用
- 为什么javascript:void(0)在Firefox中不起作用
- 列表框选择“计数不起作用”不起作用