我很难理解JavaScript Promises。我在我的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);
});
}
我查看了类似的问题,但无法得到答案。感谢帮助。
答案 0 :(得分:2)
因此,当您致电getParticipation
时发生的事情是forEach
循环一直在运行,Participation.findOne
的所有个别承诺都是已创建但尚未解决。执行不会等待他们解决并在forEach
之后继续,解决顶级承诺challengesArray
,该承诺在此时仍为空。之后,forEach
中创建的承诺开始解析,但结果现在已丢失。
另外,正如Bergi在评论中提到的,嵌套承诺被认为是anti-pattern;承诺应该链接,而不是嵌套。
你想要的是使用类似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
});
}