为何执行console.log打印时数组为空?该如何等待MongoDB返回数据后使用数组?
问题核心与时序错位原因
你对执行时序的判断完全正确,原有代码的逻辑断层来自三个具体问题:
db.collection().find().forEach()是基于MongoDB异步游标的遍历方法,本身不会阻塞线程,每拉取到1条文档才会触发一次push回调,全量遍历完成的时机远晚于同步代码的执行时机- 代码在调用forEach后立刻执行
client.close(),此时游标还未开始从服务器拉取全量数据,提前关闭连接会直接中断数据流,极端情况下数组会完全为空 consoleLogNumbers()是在数据库连接回调注册完成后立刻同步执行的,此时所有push操作根本还未触发,自然拿不到填充后的数组
可直接落地的修复方案
方案1:最小改动适配原有回调写法
保留你原本的遍历逻辑,把后续执行的代码迁移到forEach的完成回调中,调整客户端关闭的时机:
const phoneNumbers = []; MongoClient.connect(url, (err, client) => { // 优先捕获连接阶段的错误 if (err) { console.error('数据库连接失败', err); return; } const db = client.db('covid-poke-numbers'); // forEach 支持三个回调参数:单条文档处理逻辑、全量遍历完成逻辑、遍历错误捕获逻辑 db.collection('phone-numbers').find().forEach( number => { phoneNumbers.push(number.phoneNumber); }, () => { // 全量遍历完成后再执行打印逻辑 consoleLogNumbers(phoneNumbers); // 处理完全部数据后再关闭连接 client.close(); }, (err) => { console.error('文档遍历异常', err); client.close(); } ) }); function consoleLogNumbers(list) { console.log(list); }
方案2:更易维护的async/await写法
把数据库查询逻辑封装成可复用的Promise方法,后续需要用到号码数组的位置直接await取结果即可,避免回调嵌套:
async function getPhoneNumbers() { const client = await MongoClient.connect(url); const db = client.db('covid-poke-numbers'); // 直接把游标转成完整数组,无需手动push const docList = await db.collection('phone-numbers').find().toArray(); const phoneNumbers = docList.map(doc => doc.phoneNumber); // 数据处理完成后及时关闭连接 client.close(); return phoneNumbers; } // 拿到完整数组后再执行业务逻辑 getPhoneNumbers().then(list => { consoleLogNumbers(list); }); function consoleLogNumbers(list) { console.log(list); }
避坑提示
- 所有依赖数据库查询结果的逻辑,必须放到查询完成的对应回调/Promise链中执行,不要跨异步边界硬取全局变量的值
- 客户端关闭操作一定要放在数据拉取、处理全部完成之后,不能紧跟在查询调用后直接书写
- 尽量通过函数参数/返回值传递数组数据,减少裸全局变量的使用,避免其他逻辑意外修改数组内容
内容的提问来源于stack exchange,提问作者uster1
相关产品推荐
相关产品推荐

