Javascript 在for…of循环而不是forEach中创建承诺?
我希望并行执行一系列承诺,然后等待所有承诺都执行 这项工作:Javascript 在for…of循环而不是forEach中创建承诺?,javascript,foreach,promise,parse-server,for-of-loop,Javascript,Foreach,Promise,Parse Server,For Of Loop,我希望并行执行一系列承诺,然后等待所有承诺都执行 这项工作: var promises = []; objects.forEach(function(object) { let promise = new Parse.Promise.as() .then( function() { return destroy(object); } ); promises.push(promise); }); ret
var promises = [];
objects.forEach(function(object) {
let promise = new Parse.Promise.as()
.then(
function() {
return destroy(object);
}
);
promises.push(promise);
});
return Parse.Promise.when(promises);
但是如果我使用for(object of objects){…}
而不是objects.forEach(function(object){…})代码>它不工作。对于数组中的每个承诺,destroy(对象)对数组中的第一个对象执行代码>:
var promises = [];
for (object of objects) {
let promise = new Parse.Promise.as()
.then(
function() {
return destroy(object);
}
);
promises.push(promise);
});
return Parse.Promise.when(promises);
这是为什么?是的,您忘记将对象声明为循环体的局部变量(另请参见):
当然,您也不应该这样做,您应该只使用map
:
var promises = objects.map(function(object) {
return new Parse.Promise.as().then(function() {
return destroy(object);
});
});
return Parse.Promise.when(promises);
编辑:
最初我有点困惑,于是复制并粘贴了我为slack写的东西。很抱歉
正如@Bergi所说,如果您需要一个来自对象数组的承诺数组,那么通常最好使用.map()
转换现有数组。如前所述,这看起来像:
const getPromises = (objects) => {
return objects.map(object => new Parse.Promise.as()
.then(() => {
return destroy(object);
})
);
}
// No 'temp' array needed, and most important: promise variables aren't 'lost'
// Then you can similarly use this pattern:
return Parse.Promise.when(getPromises(objects));
// Or this:
return Promise.all(getPromises(objects));
我最初的答案(下面)本身有点模棱两可,希望我上面的答案能给它更多的上下文
我避免对循环或数组使用。当我发现.forEach()
时,我把它用于所有事情,假设它是我的for循环的答案。我逐渐了解到,99.99%的时间里,两者都是一种代码气味。原因:它们通常需要临时数组,这使得嵌套循环非常尴尬
当数组大小相同时,.map()
在很大程度上解决了这一问题,1:1或20:20,其他数组
方法对于非对称转换非常有用,20:1(例如:将20个产品的成本合计为一个数字,或查找列表中最大的交易):
代码中的另一个问题是失去承诺的风险!这一点很重要,如果阵列中可能有几十个或100个对象,那么在循环中触发HTTP请求将非常不可靠(最终会耗尽可用套接字)。抑制这种情况的最好方法是回报你的承诺。展示不起作用的代码为什么我也不应该使用for..of循环?@Manuel因为.map
是通过转换从旧数组创建新数组的标准方法(只要需要1:1映射)@Manuelmap
更少混乱,更少的错误空间,更多的可读性,非常好,谢谢大家,伟大的链接@Bergi充分解释了这个概念。嗨,丹,你所说的“99.99%的代码气味”到底是什么意思。。。从一个简单的例子来看这并不明显,但方法很简单。。。参见编辑。你的意思是“销毁”在“Parse.Promise.when”之前执行?是的。Destroy应该被设计成一个完成对象工作的clousure,可能会返回Destroy()
方法,这样调用的代码在完成后就可以运行:users.map(u=>u.Destroy())
为什么Parse.Promise.when()不调用Destroy
?据我所知,destroy
只有在链中的第一个承诺调用它时才被调用,Parse.Promise.when()代码>。所以顺序应该是Parse.Promise.when()
->Parse.Promise.as()
->destroy()
。
const getPromises = (objects) => {
return objects.map(object => new Parse.Promise.as()
.then(() => {
return destroy(object);
})
);
}
// No 'temp' array needed, and most important: promise variables aren't 'lost'
// Then you can similarly use this pattern:
return Parse.Promise.when(getPromises(objects));
// Or this:
return Promise.all(getPromises(objects));
.map - use for 1:1 array transforms, as @bergi suggests.
.reduce - useful for transforming 1 array into ANYTHING else. Need a sum or subtotal? Or results grouped by day? Use .reduce().
.filter - return only items which result in a `true` result
.find - use to avoid full array scans when only 1 item must be returned.
.some - exit array scan returning true at first opportunity
let downloadedMsgs = emails.map(m => downloadBody(m))
let recipientsCount = emails.reduce((count, m) => count + m.to.length, 0)
let onlyRecentMsgs = emails.filter(m => m.isNew)
let aRecentMsg = emails.find(m => m.isNew)
let hasNewMessage = emails.some(m => m.isNew)
// (Notice last 3 identical predicate fn's with different uses: aka pluripotency)