为何forEach异步操作后外部console.log无法打印cursor对象?
问题解析:forEach异步回调导致外部cursor无输出的原因及解决方法
核心原因
你遇到的问题本质是异步操作的执行顺序问题:
query.forEach()接受的是一个异步函数,但forEach本身不支持等待异步回调完成,会直接遍历完所有元素后立刻执行后续代码(也就是外部的console.log(cursor))。这时候所有异步回调里对cursor的赋值操作还没开始,cursor还是初始的空对象,所以外部日志无输出。- 内层的
addressArr.forEach(async (...) => {})同样存在这个问题:即使外层异步回调开始执行,内层的异步循环也不会同步完成,不过这不是外部日志无输出的直接原因,但会导致cursor的部分属性可能没被正确赋值。
解决方法:用for...of替代forEach
forEach不支持异步等待,改用for...of遍历,它可以和await配合,确保每一次循环里的异步操作完成后再继续执行后续代码:
import * as mongodb from 'mongodb'; const MongoClient = mongodb.default.MongoClient; import genSegWallet from './utils/genSegWallet.js'; const uri = 'mongodb+srv://dragonfly:xxxxxxxxxxxxxxxxxx.5fsiovo.mongodb.net/?retryWrites=true&w=majority'; const client = new MongoClient(uri); async function getAddrs() { const query = await client.db('users').collection('userAddress').find().toArray(); let cursor = {}; // 用for...of遍历query,支持await等待异步操作 for (const entry of query) { // 对象属性读取是同步操作,不需要加await const username = entry['username']; const mnemonic = entry['address']['mnemonic']; const address = await genSegWallet(mnemonic); const addressArr = Object.values(address); cursor[username] = {}; // 内层同样用for...of确保赋值完成 for (let index = 0; index < addressArr.length; index++) { const addr = addressArr[index]; // const bal = await getBal(addr); const bal = 0; cursor[username][index] = { 'address': addr, 'balance': bal }; } console.log(cursor); // 打印当前已完成的赋值 } console.log(cursor); // 所有异步操作完成后,cursor已被完全赋值 return cursor; }
额外说明
- 原代码里
await entry['username']是多余的:entry是从toArray()获取的同步对象,读取属性不需要异步等待,直接取值即可。 - 如果需要并行处理所有异步任务(而非顺序执行),可以用
Promise.all封装所有异步操作,不过对于需要按顺序修改cursor的场景,for...of的可读性更好。
内容的提问来源于stack exchange,提问作者Vidwat Kanade
相关产品推荐
相关产品推荐

