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

为何调用push后数组仍为空?MongoDB异步查询引发的问题

问题分析

你碰到的核心问题其实是异步操作的执行顺序,和作用域关系不大哦。User.findById()是异步方法——它的回调函数要等数据库查询完成后才会触发,但forEach是同步遍历数组的方法。当你执行到console.log(users)时,所有findById的回调都还没来得及执行,users数组自然还是空的。

解决方案1:用async/await + Promise.all(推荐)

这是最直观清晰的写法,先把每个异步查询转换成Promise,再用Promise.all等待所有查询完成:

const usersList = camp.usersList; 

// 把每个findById调用包装成Promise
const userPromises = usersList.map(userId => {
  return User.findById(userId).catch(err => {
    console.error(err);
    res.redirect('/admin/db');
    throw err; // 抛出错误让Promise.all能感知到异常
  });
});

// 这段代码要放在async函数里,因为用到了await
try {
  const users = await Promise.all(userPromises);
  console.log(users); // 这里就能得到预期的[user1, user2, ...]
  // 接下来可以用users做后续业务处理
} catch (err) {
  res.redirect('/admin/db');
}

解决方案2:Promise链式调用(兼容旧环境)

如果你的运行环境不支持async/await,可以用Promise.all结合then来处理:

const usersList = camp.usersList; 

const userPromises = usersList.map(userId => {
  return User.findById(userId).catch(err => {
    console.error(err);
    res.redirect('/admin/db');
    throw err;
  });
});

Promise.all(userPromises)
  .then(users => {
    console.log(users); // 这里就是填充完成的用户数组
    // 后续操作写在这里
  })
  .catch(err => {
    res.redirect('/admin/db');
  });

再给你理清楚原代码的执行顺序

  1. 初始化users为空数组
  2. 执行usersList.forEach,遍历每个userId,立即触发User.findById(但数据库查询是异步的,回调还没执行)
  3. 遍历完成后,立刻执行console.log(users),此时所有findById的回调都还没跑,所以输出空数组
  4. 过一会儿数据库查询陆续完成,回调函数才开始执行,把user push到users里,但这时候console.log早就执行完了

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:30:24