Promise使用咨询:嵌套查询写法是否正确及无嵌套实现方案
关于Promise嵌套写法的疑问解答
嘿,你的嵌套写法其实是完全正确的,能顺利完成车票和关联列车的查询逻辑~不过确实有更清爽的无嵌套写法,能让代码可读性更强,还能避免所谓的“回调地狱”问题,下面给你拆解一下:
首先先贴出你的原代码方便对照:
router.get('/ticket/:id', isLoggedIn, (req, res) => { Ticket.findById(req.params.id) .populate('passengers') .exec() .then(foundTicket => { Train.findById(foundTicket.trainDetails._id) .exec() .then(foundTrain => { res.render("ticket",{ticket:foundTicket, train:foundTrain}); }) .catch(err => { console.log(err) }) }) .catch(err => { console.log(err) });
一、原写法的正确性确认
你的嵌套逻辑是没问题的:先通过Ticket.findById拿到车票数据,再在第一个then里用车票的trainDetails._id查询列车,最后渲染页面。这种写法能正常工作,但嵌套层级多了之后,代码会变得难以维护,所以可以用Promise的链式特性或者async/await来优化。
二、无嵌套的优化方式
方式1:Promise链式调用(保留Promise语法)
利用then可以返回新Promise的特性,我们可以把嵌套的Promise展开成链式调用。不过要注意:如果需要同时保留foundTicket和foundTrain两个数据,不能直接返回列车查询的Promise(否则下一个then会丢失车票数据),可以用Promise.all来同时处理两个异步操作:
router.get('/ticket/:id', isLoggedIn, (req, res) => { Ticket.findById(req.params.id) .populate('passengers') .exec() // 第一个then拿到车票后,返回一个包含车票和列车查询Promise的数组 .then(foundTicket => { return Promise.all([ Promise.resolve(foundTicket), // 把已有车票数据包装成Promise Train.findById(foundTicket.trainDetails._id).exec() // 列车查询Promise ]); }) // 解构数组拿到两个结果 .then(([foundTicket, foundTrain]) => { res.render("ticket", { ticket: foundTicket, train: foundTrain }); }) // 统一捕获所有错误(不需要每个Promise单独写catch了) .catch(err => { console.log(err); });
方式2:async/await(更直观的同步式写法)
如果你觉得Promise链式还是有点绕,async/await会更适合新手,它能把异步代码写成类似同步代码的样子,可读性极强:
router.get('/ticket/:id', isLoggedIn, async (req, res) => { try { // 用await等待车票查询完成,拿到结果 const foundTicket = await Ticket.findById(req.params.id).populate('passengers').exec(); // 再用await等待列车查询完成 const foundTrain = await Train.findById(foundTicket.trainDetails._id).exec(); // 两个数据都拿到后渲染页面 res.render("ticket", { ticket: foundTicket, train: foundTrain }); } catch (err) { // 统一捕获所有异步操作的错误 console.log(err); } });
总结
你的原嵌套写法是有效的,但上面两种无嵌套的写法能让代码更整洁易维护,尤其是当后续需要添加更多异步逻辑时,优势会更明显。如果是刚接触Promise,推荐先从async/await入手,理解成本更低~
内容的提问来源于stack exchange,提问作者Praveen C.K.
相关产品推荐
相关产品推荐

