forEach Loop中的asynchronousfindOne()操作

我很难理解JavaScript的承诺。 我正在寻找符合一定条件的对象的Mongoose模型,如果它们存在,我想将对象变成一个普通的JS对象,并添加一个属性。

不幸的是,我无法将自己的头围绕在如何确保我的forEach循环将在我的诺言最终解决之前完全运行。 请看我的代码。

 // Called to check whether a user has participated in a given list of challenges participationSchema.statics.getParticipation = function(user, challenges) { return new Promise((resolve, reject) => { challengesArray = []; challenges.forEach((challenge) => { // Model#findOne() is Async--how to ensure all these complete before promise is resolved? Participation.findOne({user, challenge}) .then((res) => { if (res) { var leanObj = challenge.toObject(); leanObj.participation = true; challengesArray.push(leanObj); } }) .catch(e => reject(e)); }) console.log("CHALLENGES ARRAY", challengesArray); // Challenges Array empty :( resolve(challengesArray); }); } 

我已经看过类似的问题,但无法得到答案。 感谢帮助。

所以,当你调用getParticipation时发生的事情是forEach roop一直运行, Participation.findOne所有单个promise都被创build,但还没有解决 。 执行不会等待它们解决,并在forEach之后继续,解决顶级promise forEach ,在这一点上仍然是空的。 过了一段时间,在forEach创build的承诺开始解决,但是他们的结果现在丢失了。

另外,正如Bergi在评论中提到的,嵌套承诺被认为是反模式 ; 承诺应该被链接,而不是嵌套。

你想要的是使用像Promise.all等所有的承诺先完成,然后你过滤掉所有不存在的结果,最后返回数组。

 participationSchema.statics.getParticipation = function(user, challenges) { return Promise.all(challenges.map(challenge => { return Participation.findOne({user, challenge}).then(result => { if (result) { var leanObj = challenge.toObject(); leanObj.participation = true; return leanObj; } }); }) // at this point, results contains an array of `leanObject` and `undefined` depending if the `findOne` call returned anything and the code withing the `if` above was run .then((results) => { return results.filter(result => !!result) // filter out `undefined` results so we only end up with lean objects }); }