如何让回调函数等待数据库调用完成?Node.js后端求助
问题分析
你遇到的核心问题是:forEach 不支持异步等待——哪怕给它传了async回调函数,forEach也会直接遍历完所有元素,不会等待每个回调里的await操作完成。这就导致后续处理rows的代码(以及最终的res.send)在异步DB调用getIdDetails结束前就执行了,自然拿不到datas的值。
另外你的代码还有几个额外问题:
- 第二个
forEach里引用了未定义的row变量,应该是dets.dept_name finally里调用res.send会导致重复发送响应(then或catch里已经可能发送了)await和.then()混用,代码逻辑混乱CommonUtil.formatDetails传入的是整个rows数组,看起来应该是处理单个row
解决方案:用
Promise.all + map替代forEach map可以把每个row处理成一个Promise,再用Promise.all等待所有Promise完成,确保所有异步DB调用都结束后再处理结果和发送响应。
修正后的代码如下:
this.router.get("/:version/:dept/:id", async (req: any, res: any) => { try { logger.trace("getDetails call initialized"); const dept = req.params.dept; const id = req.params.id; const deptDao = new deptDAO(); let finalDetails = []; let simpleDetail = {}; // 首次DB调用 const rows = await deptDao.getdetails(dept, id); // 用map生成所有异步操作的Promise数组,再用Promise.all等待全部完成 await Promise.all(rows.map(async (row: any) => { if (row.dept_name === "Science") { try { const idDao = new IDDao(); // 统一用await替代then,逻辑更清晰 const result = await idDao.getIdDetails(dept, row.valueId); if (result[0]?.std_details?.datas) { row.datas = result[0].std_details.datas; } } catch (error) { logger.error('failed', error); } } else { // 修正为处理单个row而非整个rows数组 CommonUtil.formatDetails(dept, row); } })); // 现在所有异步操作都完成了,可以安全处理rows rows.forEach((dets) => { if (dets.dept_name === "Science") { simpleDetail = dets; } else { finalDetails.push(dets); } }); // 发送响应 res.status(200).send({ status: "success", depts: finalDetails, dept: simpleDetail }); } catch (ex) { logger.error('整体请求失败', ex); res.status(500).send({ status: "failed", message: ex.message }); } });
关键改动说明
- 把路由回调改成
async函数,内部用await替代.then()链式调用,代码更简洁易读 - 用
rows.map(async row => {...})生成每个row对应的异步处理Promise,再用await Promise.all(...)等待所有异步DB调用完成 - 移除原代码中的
.then()、.catch()、.finally()链式结构,改用try/catch处理全局错误 - 修正
CommonUtil.formatDetails的参数,改为处理单个row - 移除
finally里的res.send,避免重复发送响应,确保只有在所有操作完成后才发送成功响应
内容的提问来源于stack exchange,提问作者Ajay Antonyraj
相关产品推荐
相关产品推荐

