2017-06-16 79 views
0

我最近开始使用promise,因此,例如,我可以等到在执行下一个函数之前用x个记录更新数据库。我发现自己正在计算循环迭代,以便在正确的时间解决承诺。例如:如何避免计数JavaScript Promises中的循环迭代

var updateAccounts = function(accounts) { 
 
    var promise = new Promise(function(resolve, reject) { 
 
     var counter = 0; 
 
     accounts.forEach(function(account) { 
 

 
     db.collection('accounts').update({ 
 
      name: account.name 
 
     }, { 
 
      $set: { 
 
      balance: account.balance 
 
      } 
 
     }); 
 
     counter++ 
 
     if (counter == accounts.length) { 
 
      resolve('accounts updated'); 
 
     } 
 
     }); 
 
    } 
 
    }); 
 
    return promise; 
 
}

有没有办法等到循环没有计算迭代完成了吗?这只是一种黑客行为,但我不确定它是否真的存在问题。

+0

您并未等待更新完成。循环是同步的,更新不是。当循环已经结束时,它们在并行中发生。查看[Promise.all()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) – Thomas

+0

这是mongodb吗?猫鼬? – trincot

+0

@Thomas所以​​你的意思是promise.all,每个更新都是一个承诺? – chuckieDub

回答

4

根据MDN

无极对象表示异步操作的最终完成(或失败),并且其结果值。

基本上这意味着Promise应跟踪单个异步操作的结果。

但是,在您的示例中,您在一个Promise内执行了多个异步操作(即​​)。你不得不求助于一个互动计数来追踪完整性,而不是依靠这样做的承诺。

要解决此问题(双关意图:D),您的每个异步请求应该都有自己的Promise

由于您有多个更新并因此有多个承诺,所以您可以使用Promise.all来捕获所有承诺成功完成时的情况。

这里是你的代码示例的快速适应:

var updateAccounts = function(accounts) { 
    var promises = []; 
    accounts.forEach(function(account) { 
     var promise = new Promise(function(resolve, reject) { 
      db.collection('accounts').update({ 
       name: account.name 
      }, { 
       $set: { 
       balance: account.balance 
       } 
      }); 
     }); 
     promises.push(promise); 
    }); 

    Promise.all(promises).then(function(arrPromises) { 
     console.log("All promises resolved."); 
    }).catch(function(failedPromise) { 
     console.log("Something failed."); 
    }); 

} 

从我的例子中唯一缺少的是​​后调用resolve成功执行。更新成功完成后,您必须调用resolve,或者如果更新失败,则必须调用reject。这是告诉它已经完成的承诺。

我的代码示例在没有这个功能的情况下无法正常工作,但是从原始代码示例中不清楚哪里应该指定​​的回调 - 所以我省略了它。

0

你可以在foreach后试试吗?

var updateAccounts = function(accounts) { 
 
    var promise = new Promise(function(resolve, reject) { 
 
     ... 
 
     accounts.forEach(function(account) { 
 
     ... 
 
     }); 
 
    <---Here<-- 
 
    } 
 
    }); 
 
    return promise; 
 
}
这似乎很奇怪要检查内循环的foreach完成。也许你想确保帐户数组有一些元素?您也可以在循环外检查零或非零长度。

+0

我想我不明白异步BS同步,但基本上我想确保循环已完成,然后再移动到下一个函数。什么是最好的方法来做到这一点? foreach是否默认这样做? – chuckieDub

+0

我最终取消选择其他答案并选择这一个。你是对的,我可以在循环后解决。出于某种原因,我有一种经历让我觉得我必须计算循环,这是不正确的。谢谢你,你救了我很多时间! – chuckieDub

+1

这个答案是完全错误的。我强烈建议您重新阅读下面的答案。 – Randall444