Да, вы правы, проблема в том, что промисы не решаются до того, как сервер отправит ответ. Эта часть кода является виновником:
stepsArray.forEach(function (step) {
Steps.findOne({ _id: step }, (err, foundStep) => {
//push to array that was definedin first part
workflowStepCombined.push(foundStep);
});
});
Array.forEach
сложно с асинхронными обратными вызовами, в вашем случае вы ожидаете, что каждый l oop будет выполняться и разрешаться до следующего, так что при конец l oop, результат всех запросов findOne
будет в массиве workflowStepCombined
, однако это не так, вы можете проверить эту статью, чтобы узнать, почему .
Простым исправлением было бы использовать Promise.all
следующим образом:
Promise.all(stepsArray.map(stepId => Steps.findOne({_id: stepId})))
.then(workflowStepCombined => {
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
})
Однако, поскольку sepsArray
представляет собой массив шагов рабочего процесса _id
s, вы можете сделать использование одного поискового запроса вместо выполнения нескольких запросов в al oop. Примерно так:
Steps.find({ _id: { $in: stepsArray } })
Это должно вернуть массив, содержащий все объекты step, указанные в stepsArray
, поэтому нет необходимости в l oop и pu sh. В сочетании с предыдущим запросом конечная точка должна быть примерно такой:
app.get("/new/:workflowID", function (req, res) {
if (req.isAuthenticated()) {
const workflowID = req.params.workflowID;
Workflow.findOne({ workflowName: workflowID }, function (err,foundWorkflow) {
const stepsArray = foundWorkflow.workflowStepArray;
Steps.find({ _id: { $in: stepsArray } }, function(error, workflowStepCombined) {
res.render("contracts/" + workflowID, {
userID: req.user.username,
workflow: workflowStepCombined,
});
})
});
} else {
res.redirect("/");
}
});
Не забывайте перехватывать и обрабатывать возможные ошибки