NodeJS使用Mongoose时如何等待异步函数执行完成再运行后续代码
问题根因
你遇到的是Node.js异步IO的执行顺序问题:
- Mongoose的
findOne是异步操作,传入的回调函数会在数据库查询完成后才被推入事件队列执行 - 主线程不会等待回调执行,会直接运行你写在forEach后面的打印、渲染逻辑,此时所有
Product.findOne的查询还没完成,prodAndQty自然是空数组。
修复方案(推荐async/await写法,可读性更高)
将异步回调改写为async/await语法,用Promise.all批量等待所有商品查询完成后再执行渲染:
// 给路由处理函数加上async关键字 router.get('/cart', async function (req, res) { try { const user = await User.findOne({ username: req.user.username }); if (!user) { return res.render('cart', { doc: null, qty: 0, products: null }); } const prodEntries = Object.entries(user.shoppingCart); // 把所有商品查询包装为Promise数组,并行执行提高效率 const prodAndQty = await Promise.all( prodEntries.map(async (entry) => { const product = await Product.findOne({ id: entry[0] }); return [product, entry[1]]; }) ); // 此时数组已经完全填充,可以正常打印、渲染 console.log(prodAndQty); res.render('cart', { doc: user, qty: prodEntries.length, products: prodAndQty }); } catch (err) { console.log(err); // 错误场景也需要给前端返回响应,避免请求挂起 res.render('cart', { doc: null, qty: 0, products: null }); } });
改动说明
- 回调嵌套改为async/await语法,消除异步执行顺序混乱的问题
- 用
map替代forEach生成Promise数组,通过Promise.all等待所有数据库查询执行完成 - 统一用try/catch捕获所有异步操作的异常,避免服务进程崩溃
内容的提问来源于stack exchange,提问作者Gabriel López Valencia
相关产品推荐
相关产品推荐

