过去 6 个月以来,我一直在使用 NodeJS 进行编码,但我仍然对异步和 Promise 概念没有清晰的了解。现在谈到这个问题,我将使用 Mongoose 从 MongoDB 获取一条记录,该记录可能有branchId,在每次迭代中执行一个简单的 for 循环,并执行异步的 MongoDB 操作(因为 MongoDB/Mongoose 操作是 promise )。如您所知,for 循环是同步的,但我的函数在 for 循环结束之前返回值。这是怎么发生的?如果我的问题不清楚,请附上代码,将其作为评论。
const restManageChef = (params, query, body) => {
if (query && parseBoolean(query.superChef)) {
body = Object.assign(body, { role: 'SUPER-CHEF' });
} else {
body = Object.assign(body, { role: 'RES-CHEF' });
}
return restPUT(params, query, body).then(chef => {
return userModel
.findOne({ restaurantCode: chef.restaurantCode, type: 'RES-ADMIN' })
.then(resAdminDetails => {
log.debug({ Chef: chef }, 'Chef Details');
if (chef.role === 'SUPER-CHEF') {
log.debug({ BranchIds: resAdminDetails.branchIds }, 'BranchIds');
for (let i = 0; i < resAdminDetails.branchIds.length; i) {
log.debug({ BranchIds: resAdminDetails.branchIds[i] }, 'BranchIds');
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({ Restaurant: restaurant }, 'Restaurant Details');
})
.catch(err => {
log.error({ err });
throw err;
});
}
return chef;
} else if (chef.role === 'RES-CHEF') {
for (let i = 0; i < resAdminDetails.branchIds.length; i++) {
log.debug({ BranchIds: resAdminDetails.branchIds[i] }, 'BranchIds');
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({ Restaurant: restaurant }, 'Restaurant Details');
})
.catch(err => {
log.error({ err });
throw err;
});
}
return chef;
}
});
});
};
PushChefId函数
const pushChefId = (restaurantCode, chefId) => {
return userModel
.findOneAndUpdate({ restaurantCode }, { $addToSet: { chefIds: chefId } })
.exec()
.then(resAdmin => {
if (!resAdmin) return Promise.reject(`No RES-ADMIN found with restaurantCode - ${restaurantCode}`);
return storeModel.findByIdAndUpdate(restaurantCode, { $addToSet: { chefIds: chefId } }, { new: true });
});
};
最佳答案
您正在以同步方式使用异步(在您的情况下是 Promise)代码。
这是一个异步调用:
pushChefId(resAdminDetails.branchIds[i], chef.pkid)
.then(restaurant => {
log.debug({
Restaurant: restaurant
}, 'Restaurant Details');
})
.catch(err => {
log.error({
err
});
throw err;
});
基本上,您一个接一个地触发此异步调用,并立即跳到 return 语句,而无需等待每个触发的异步调用完成。
在您的情况下,我绝对建议您考虑的一种方法是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
}
);
};
当然可以通过并行 Promise 触发等进行优化。但对于基本解释应该足够了。
关键的变化在这里:
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;
}
};
async
函数上下文中的 await
关键字将等待 Promise
值的解析,并在不带 的情况下返回该值。 code>Promise
包装器,只是原始值或将接收抛出的错误,从而允许使用基本的 try catch
以同步方式捕获它。
您可以阅读有关异步等待的更多信息 here .
希望这能澄清一点。
关于javascript - 了解 NodeJS 中的异步和 Promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50180997/