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映射)@Manuel
map
更少混乱,更少的错误空间,更多的可读性,非常好,谢谢大家,伟大的链接@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)