forEach循环内变量修改未保存 循环外访问users数组结果异常
问题原因
核心是异步操作时序错误,具体有两个问题:
db.get()是返回Promise的异步操作,.then()里的回调逻辑会进入微任务队列,必须等当前所有同步代码执行完才会运行。你在发起db.get()请求后立刻判断profile是否为空,此时回调还没执行,profile始终是初始的undefined,判断逻辑和后续的User实例化、push操作根本拿不到数据库返回的真实值。forEach本身不支持异步等待,就算给forEach的回调加上async关键字,它也不会等待每个迭代里的异步操作完成,循环会直接跑完,后续的console.log(users)会在所有数据库请求返回前就执行,自然拿不到正确结果。
解决方案
不要用forEach处理异步迭代,改用map配合Promise.all,等所有数据库查询完成后,再统一做过滤、User实例组装的逻辑。
async/await 写法(推荐)
const getValidUsers = async () => { // 并行发起所有成员的数据库查询,等待全部结果返回 const recordList = await Promise.all( members.map(async (member) => { const rawValue = await db.get(member.id) return { member, profile: JSON.parse(rawValue) } }) ) // 所有数据就绪后再做过滤和实例组装 const users = recordList .filter(({ profile }) => profile !== null) .filter(({ profile }) => profile.bank + profile.cash > 0) .map(({ member, profile }) => new User(member, profile)) console.log(users) return users } // 调用函数获取结果 getValidUsers()
纯Promise链式写法
如果项目环境不支持async/await,可以用纯Promise写法:
Promise.all( members.map(member => { return db.get(member.id).then(rawValue => ({ member, profile: JSON.parse(rawValue) })) }) ).then(recordList => { const users = recordList .filter(({ profile }) => profile !== null) .filter(({ profile }) => profile.bank + profile.cash > 0) .map(({ member, profile }) => new User(member, profile)) console.log(users) })
注意事项
- 所有依赖异步返回结果的逻辑,必须写在
await之后,或者.then()的回调范围内,不能紧跟在异步发起语句后面同步执行。 - 不要尝试用普通for循环加await串行查询(除非你明确需要串行),
Promise.all的并行查询性能远高于串行请求。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

