我很难理解JavaScript承诺。我正在搜索我的猫鼬模型,以了解符合特定条件的对象,如果它们存在,我想将对象放入普通的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
循环一直运行,Participation.findOne
的所有个人承诺都是创建但尚未解决的。执行不等待他们解决并在forEach
之后继续进行,而是解决了当时仍然是空的顶级Promise challengesArray
。此后的某个时候,forEach
中创建的承诺开始解决,但他们的结果现在丢失了。
此外,正如伯吉(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
});
}