如何确保Firebase数据库调用完成后再使用统计数据?
解决Firebase异步请求未完成就渲染统计数据的问题
问题核心
你遇到的问题是异步操作未等待完成就执行后续逻辑:
- 第一个
then中,遍历userMatches发起的get(ref(database, \matches/${v}`))是异步请求,但forEach不会等待这些请求完成,就直接执行后续代码并进入下一个then。此时userMatches里还是存储的match ID,未被替换为完整的match对象,导致map(v => v.category)得到undefined`。 - 后续
then链没有等待前置异步操作全部完成,依赖异步数据的逻辑自然出错。
修正后的代码
async function addStats() { let userMatches, wins, losses, ties; // 获取用户的match ID列表 const matchesSnapshot = await get(ref(database, `users/${user.uid}/matches`)); userMatches = Object.values(matchesSnapshot.val()); // 并行获取所有match的详细数据,等待全部完成 const matchPromises = userMatches.map(matchId => get(ref(database, `matches/${matchId}`))); const matchSnapshots = await Promise.all(matchPromises); userMatches = matchSnapshots.map(snap => snap.val()); // 渲染比赛数量统计 addStat('matchesPlayed', userMatches.length); // 计算并渲染最喜爱的比赛类别 const categories = userMatches.map(v => v.category); addStat('favCategory', getMode(categories)); // 并行获取胜负平数据,提升效率 const [winsSnapshot, lossesSnapshot, tiesSnapshot] = await Promise.all([ get(ref(database, `users/${user.uid}/wins`)), get(ref(database, `users/${user.uid}/losses`)), get(ref(database, `users/${user.uid}/tied`)) ]); wins = winsSnapshot.exists() ? winsSnapshot.val() : 0; losses = lossesSnapshot.exists() ? lossesSnapshot.val() : 0; ties = tiesSnapshot.exists() ? tiesSnapshot.val() : 0; // 渲染胜负平统计 addStat('wlt', [wins, losses, ties].join('/')); }
关键修改说明
- 改用
async/await替代嵌套then,逻辑更直观,便于明确等待异步操作完成。 - 用
Promise.all并行处理多异步请求:- 所有match详情请求先打包成Promise数组,等待全部完成后再更新
userMatches,确保后续逻辑拿到的是完整的match对象。 - 胜负平的三个请求并行发起,减少总等待时间。
- 所有match详情请求先打包成Promise数组,等待全部完成后再更新
- 移除冗余的
then链嵌套,每一步都明确等待依赖的异步操作完成后再执行。
内容的提问来源于stack exchange,提问作者Anay
相关产品推荐
相关产品推荐

