Node+Express+EJS异步获取MongoDB数据后渲染页面的问题
解决异步调用导致的
results值为undefined问题 你猜的没错,问题确实出在异步调用的处理上。咱们一步步拆解:
你的GetResults函数里用了MongoDB的回调式find()方法,这个方法是异步执行的——也就是说,当你在路由里调用DBhandler.GetResults(req,res)时,函数会立刻返回(此时数据库查询还没完成),所以你拿到的results自然是undefined,而回调里的return result根本不会把值传递回路由里的变量。
下面给你几种靠谱的解决方法,按推荐程度排序:
方法1:用async/await + Promise封装(最优雅,代码可读性高)
首先把你的GetResults改成返回Promise的形式,Mongoose的方法本身就支持Promise,直接返回即可:
exports.GetResults = function (req, res) { console.log(req.body); // Mongoose的find()默认返回Promise,直接return return ResultModel.find({}) .then(result => { console.log('this is the value of result from the getresults call: ', result); return result; }) .catch(err => { console.log('SOMETHING WENT WRONG GETTING RESULTS: ', err); throw err; // 抛出错误让路由层处理 }); }
然后在路由里用async/await等待异步操作完成:
// 给路由函数添加async关键字 router.get('/results', isLoggedIn, async function(req,res){ try { const results = await DBhandler.GetResults(req,res); console.log('value of results right before it is passed to results.ejs: ', results); res.render('results.ejs', {results:results}); } catch (err) { // 统一处理查询出错的情况 console.error(err); res.status(500).send('Failed to fetch results'); } });
方法2:直接在数据库函数的回调里渲染页面(最简单,适合快速解决)
如果你不想折腾Promise,也可以把渲染逻辑直接放到数据库查询的回调里,虽然会让数据库函数和Express响应逻辑耦合,但小型项目里用起来很方便:
修改GetResults函数:
exports.GetResults = function (req, res) { console.log(req.body); ResultModel.find({},function(err, result){ if(err){ console.log('SOMETHING WENT WRONG GETTING RESULTS: ', err); res.status(500).send('Failed to fetch results'); }else{ console.log('this is the value of result from the getresults call: ', result); res.render('results.ejs', {results:result}); // 直接在这里完成渲染 } }); }
然后路由里只需要调用函数就行:
router.get('/results',isLoggedIn, function(req,res){ DBhandler.GetResults(req,res); // 不用接收返回值,回调里已经处理了所有逻辑 });
方法3:给GetResults传递回调函数(传统异步处理方式)
这种是早期Node.js常用的回调模式,可读性不如Promise,但也能解决问题,给你做个参考:
修改GetResults接受一个回调参数:
exports.GetResults = function (req, res, callback) { console.log(req.body); ResultModel.find({},function(err, result){ if(err){ console.log('SOMETHING WENT WRONG GETTING RESULTS: ', err); callback(err, null); }else{ console.log('this is the value of result from the getresults call: ', result); callback(null, result); } }); }
然后路由里传入回调处理结果:
router.get('/results',isLoggedIn, function(req,res){ DBhandler.GetResults(req,res, function(err, results){ if(err){ console.error(err); res.status(500).send('Failed to fetch results'); } else { console.log('value of results right before it is passed to results.ejs: ', results); res.render('results.ejs', {results:results}); } }); });
总结一下,最推荐方法1,用async/await+Promise的组合,代码清晰易维护,也符合现代Node.js的异步编程习惯,还能很好地处理错误场景。
内容的提问来源于stack exchange,提问作者mo_maat
相关产品推荐
相关产品推荐

