Flutter Web从FireStore取数计算耗时过长,求优化方案
Flutter Web 积分计算流程性能优化方案
核心性能瓶颈
当前流程的主要耗时点集中在:
- 步数计算时每日发起一次Firestore文档请求,日期区间越长请求量越大
- 用户积分计算串行执行,未利用异步并行能力
- 循环中频繁调用
setState,触发多次UI重绘
针对性优化建议
1. 重构步数查询逻辑,大幅减少Firestore请求
原代码中getStepScores通过Future.forEach循环查询每日步数,每个用户在一个月区间内会发起30+次请求。可以改为一次性获取用户所有步数数据,本地计算分数:
Future<int> getStepScores(String userId, DateTime startDate, DateTime endDate) async { List<DateTime> betweenDates = getBetweenDays(startDate, endDate); int stepScores = 0; // 一次性获取用户所有步数文档,而非每日请求 final doc = await _db.collection("user_step_count").doc(userId).get(); if (!doc.exists) return 0; final stepData = doc.data()!; for (var date in betweenDates) { final dateString = "${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}"; if (stepData.containsKey(dateString)) { final dailyStepInt = stepData[dateString] as int; stepScores += dailyStepInt < 0 ? 0 : dailyStepInt > 10000 ? 100 : ((dailyStepInt / 1000).floor()) * 10; } } return stepScores; }
此优化将步数请求从O(N)降为O(1),N为日期区间天数
2. 用户计算并行化,替换串行循环
原代码通过for循环串行处理每个用户的积分计算,改为用Future.wait并行执行所有用户的计算任务:
// 替换原串行循环 final updatedUsers = await Future.wait( userDataList.map((user) => ref .read(rankingProvider.notifier) .calculateItem(user, firstDateOfMonth, now)) ); // 一次性更新状态 setState(() { _initialUserDataListState = false; _userContractType = getUserContractType; _userContractName = getUserContractName; _userDataList.addAll(updatedUsers); // 直接在这里完成排序 _userDataList.sort((a, b) => b!.totalScore.compareTo(a!.totalScore)); });
并行处理能大幅缩短多用户场景下的总耗时,充分利用异步并发能力
3. 优化状态更新逻辑,避免频繁UI重绘
原循环中每处理一个用户就调用setState,会触发多次UI重建。改为所有用户计算完成后一次性更新状态,同时直接在状态更新时完成排序,减少后续操作。
4. 其他细节优化
- 避免强制解包(
!):对stepScore、diaryScore等添加空值判断,避免潜在崩溃同时提升代码稳定性 - 缓存日期字符串:将日期格式化逻辑封装为工具函数,避免重复计算
- 提前过滤无效用户:在计算前先过滤掉
userId为空的用户,减少无效计算
关于加载页的建议
无论优化与否,都必须添加加载页:
- 即使优化后,Firestore网络请求仍存在不可控的延迟
- 加载页能明确告知用户当前处于处理状态,避免用户误以为页面卡顿无响应
- 可搭配进度指示器(如线性进度条),进一步提升用户体验
内容的提问来源于stack exchange,提问作者Hyejung
相关产品推荐
相关产品推荐

