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

Node.js路由代码重构求助:res.render提前执行致数据无法渲染

解决异步forEach导致res.render提前执行的问题

这个问题我之前也踩过坑!核心原因就是JavaScript的forEach不支持等待内部的异步操作完成——你在forEach里写的async回调函数会被丢进事件队列排队,主线程却直接跳过循环执行后面的console.log("second log")和res.render,所以才会出现你看到的日志顺序,模板自然拿不到if块里更新的status和marks。

下面给你两种靠谱的重构方案,按需选择:

方案一:用for...of替代forEach(串行执行,逻辑直观)

for...of是支持和await配合的,它会等待每次循环里的异步操作完成后,再进入下一次循环,确保所有元素都更新完毕后才执行res.render:

router.get('/', ensureLogin, async (req, res) => { 
  try { 
    let result = await Mock.find(); 
    // 替换forEach为for...of,支持await等待异步操作
    for (const e of result) {
      if (e.attemptedBy.includes(req.user._id)) { 
        let a_Mock = await User.findOne(
          { _id: req.user._id, "attemptedMock.setNo": e.setNo },
          { attemptedMock: 1 }
        ); 
        // 这里的更新会同步到result数组里
        e.status = "Attempted";
        // 加存在性判断,避免找不到对应记录时报错
        e.marks = a_Mock?.attemptedMock?.[0]?.totalMarks || 0; 
        console.log(a_Mock?.attemptedMock?.[0]?.totalMarks); 
      } else { 
        e.status = "Unattempted";
        console.log('else block') 
      }
    }
    console.log("second log"); 
    // 现在result已经全部更新完成,可以放心渲染
    res.render('dashboard', { mocks: result });
  } catch (e) { 
    console.log(e); 
  }
})

方案二:用Promise.all并行处理(效率更高,适合大量数据)

如果你的Mock数据比较多,for...of串行执行会比较慢,可以用Promise.all并行发起所有异步请求,等全部完成后再继续:

router.get('/', ensureLogin, async (req, res) => { 
  try { 
    let result = await Mock.find(); 
    // 用map生成所有异步Promise,再用Promise.all等待全部完成
    await Promise.all(result.map(async (e) => {
      if (e.attemptedBy.includes(req.user._id)) { 
        let a_Mock = await User.findOne(
          { _id: req.user._id, "attemptedMock.setNo": e.setNo },
          { attemptedMock: 1 }
        ); 
        e.status = "Attempted";
        e.marks = a_Mock?.attemptedMock?.[0]?.totalMarks || 0; 
        console.log(a_Mock?.attemptedMock?.[0]?.totalMarks); 
      } else { 
        e.status = "Unattempted";
        console.log('else block') 
      }
    }));
    console.log("second log"); 
    res.render('dashboard', { mocks: result });
  } catch (e) { 
    console.log(e); 
  }
})

额外提醒

我加了?.可选链操作符和|| 0默认值,是为了避免用户的attemptedMock里没有匹配setNo的项时,出现Cannot read properties of undefined的报错,实际项目里可以根据需求调整默认值或者错误处理逻辑。

内容的提问来源于stack exchange,提问作者Deepak Soni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:32:29