You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:48:50