在 for...of 循环而不是 forEach 中创建 Promises?
Creating Promises in for...of loop instead forEach?
我想并行执行一组 Promise,然后等待所有 Promise 执行完毕。
这个有效:
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) {...});
它就不起作用了。对于数组中的每个 Promise,destroy(object);
在数组中的第一个对象上执行:
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);
这是为什么?
是的,您忘记将 object
变量声明为循环体的局部变量(另请参阅 canonical explanation):
var promises = [];
for (let object of objects) {
// ^^^
promises.push(new Parse.Promise.as().then(function() {
return destroy(object);
}));
}
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);
编辑:
最初我有点困惑,然后复制并粘贴我写的一些东西以备不时之需。对于那个很抱歉。
就像@Bergi 所说的,如果您需要 objects
数组中的 Promise 数组,那么通常最好使用 .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));
我原来的回答(下面)本身有点模棱两可,希望我上面的回答能提供更多背景信息。 :)
我避免使用 for
循环或 Array.forEach
。当我发现 .forEach()
时,我将它用于一切,假设它是我 for loops
混乱的答案。我开始了解到两者在 99.99% 的时间里都是代码味道。原因:它们通常需要临时数组,并使嵌套循环非常尴尬。
虽然 .map()
在数组大小相同时很大程度上解决了这个问题,1:1 或 20:20,但其他 Array
方法对非对称变换很有用,20:1(例如:将20种产品的成本合计为1个数,或者求列表中最大的一笔交易):
.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)
代码中的另一个问题是失去承诺的风险!这一点很重要,如果您的数组中可能有数十个或数百个对象,那么在循环中触发 HTTP 请求将非常不可靠(最终您会耗尽可用套接字)。限制这种情况的最佳方法是返回您的 Promises。
我想并行执行一组 Promise,然后等待所有 Promise 执行完毕。
这个有效:
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) {...});
它就不起作用了。对于数组中的每个 Promise,destroy(object);
在数组中的第一个对象上执行:
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);
这是为什么?
是的,您忘记将 object
变量声明为循环体的局部变量(另请参阅 canonical explanation):
var promises = [];
for (let object of objects) {
// ^^^
promises.push(new Parse.Promise.as().then(function() {
return destroy(object);
}));
}
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);
编辑: 最初我有点困惑,然后复制并粘贴我写的一些东西以备不时之需。对于那个很抱歉。
就像@Bergi 所说的,如果您需要 objects
数组中的 Promise 数组,那么通常最好使用 .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));
我原来的回答(下面)本身有点模棱两可,希望我上面的回答能提供更多背景信息。 :)
我避免使用 for
循环或 Array.forEach
。当我发现 .forEach()
时,我将它用于一切,假设它是我 for loops
混乱的答案。我开始了解到两者在 99.99% 的时间里都是代码味道。原因:它们通常需要临时数组,并使嵌套循环非常尴尬。
虽然 .map()
在数组大小相同时很大程度上解决了这个问题,1:1 或 20:20,但其他 Array
方法对非对称变换很有用,20:1(例如:将20种产品的成本合计为1个数,或者求列表中最大的一笔交易):
.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)
代码中的另一个问题是失去承诺的风险!这一点很重要,如果您的数组中可能有数十个或数百个对象,那么在循环中触发 HTTP 请求将非常不可靠(最终您会耗尽可用套接字)。限制这种情况的最佳方法是返回您的 Promises。