Вы работаете с асинхронным (в вашем случае Promises) кодом синхронно.
Это асинхронный вызов:
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({
Restaurant: restaurant
}, 'Restaurant Details');
})
.catch(err => {
log.error({
err
});
throw err;
});
По сути, вы запускаете эти асинхронные вызовы один за другим и сразу переходите к оператору возврата, даже не ожидая завершения каждого запущенного асинхронного вызова.
Единственный подход, который я определенно посоветовал бы рассмотреть в вашем случае, это async/await
, который по сути является синхронным способом написания асинхронного кода.
Это может пойти примерно так:
const decorateWithRole = (query, body) => {
return {
...body,
role: (query && parseBoolean(query.superChef) && "RES-CHEF") || "SUPER-CHEF"
};
};
const restManageChef = async(params, query, body) => {
const decoratedBody = decorateWithRole(query, body, parseBoolean);
const chef = await restPUT(params, query, body);
const resAdminDetails = await userModel.findOne({
restaurantCode: chef.restaurantCode,
type: "RES-ADMIN"
});
log.debug({
Chef: chef
}, "Chef Details");
if (["SUPER-CHEF", "RES-CHEF"].includes(chef.role)) {
log.debug({
BranchIds: resAdminDetails.branchIds
}, "BranchIds");
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({
BranchIds: resAdminDetails.branchIds[i]
}, "BranchIds");
try {
const restaurant = await pushChefId(
resAdminDetails.branchIds[i],
chef.pkid
);
log.debug({
Restaurant: restaurant
}, "Restaurant Details");
} catch (err) {
log.error({
err
});
throw err;
}
}
return chef;
}
};
const pushChefId = async(restaurantCode, chefId) => {
const resAdmin = await userModel
.findOneAndUpdate({
restaurantCode
}, {
$addToSet: {
chefIds: chefId
}
})
.exec();
if (!resAdmin) {
return Promise.reject(
`No RES-ADMIN found with restaurantCode - ${restaurantCode}`
);
}
return storeModel.findByIdAndUpdate(
restaurantCode, {
$addToSet: {
chefIds: chefId
}
}, {
new: true
}
);
};
Конечно, его можно оптимизировать с помощью параллельного запуска обещаний и т. Д. И т. Д. Но для базового объяснения должно быть достаточно.
Важное изменение здесь:
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({
BranchIds: resAdminDetails.branchIds[i]
}, "BranchIds");
try {
const restaurant = await pushChefId(
resAdminDetails.branchIds[i],
chef.pkid
);
log.debug({
Restaurant: restaurant
}, "Restaurant Details");
} catch (err) {
log.error({
err
});
throw err;
}
}
return chef;
}
};
Ключевое слово await
в контексте функции async
будет ожидать разрешения значения Promise
и возвратит его без оболочки Promise
, только необработанное значение, или получит выданную ошибку, таким образом позволяя поймать его также синхронно с базовым try catch
.
Подробнее об асинхронном ожидании вы можете прочитать здесь .
Надеюсь, это прояснит немного.