跳转到正文
YGJoon 技术博客

Flutter 项目案例(十):搜索防抖与结果竞态

发布于:
·913 字 · 约 2 分钟·作者:
400ms 防抖只能减少请求次数,无法保证响应顺序。示例用请求代次丢弃迟到结果,并分别处理地图地址和内容搜索。
Flutter 项目案例(十):搜索防抖与结果竞态文章封面
目录

搜索框的每个字符都是一次状态变化

地图地址页的输入框在 onChanged 中直接调用搜索方法。输入一串地点名称会连续发起多次查询,网络请求数量随字符变化;如果用户正在改词,旧查询可能还在后台运行。

列表搜索可以采用更节制的做法:控制器保存一个 Timer,每次输入取消上一个计时器,再等待 400ms 后刷新列表。

void onSearchChanged(String value) {
  _searchDebounce?.cancel();
  _searchDebounce = Timer(const Duration(milliseconds: 400), () {
    onRefresh();
  });
}

控制器关闭时也取消计时器并释放输入框。这样能减少快速输入时对列表和 SmartRefresher 的连续冲击。

防抖和请求取消解决不同问题

防抖控制的是“什么时候发起下一次请求”,不能自动取消已经发出的请求。假设查询 A 先开始但响应较慢,查询 B 后开始却先返回;若 A 最后覆盖列表,页面最终显示的还是旧词结果。

更完整的实现会在每次查询时保存关键词和城市,递增 requestId,并在响应返回时只接受最新编号。也可以使用可取消的网络请求,但仍需要定义取消后的界面状态。

选一个适合业务的等待时间

400ms 是交互和请求量之间的折衷。地图地点搜索可能希望更快显示结果,弱网下也可能需要更长的等待;还可以在输入长度不足时不请求,在清空时立即恢复附近列表。

调试时记录请求发起和完成时使用的关键词,比只看列表内容更容易发现乱序问题。日志应避免输出用户输入中的地址或其他隐私信息。

两个搜索页的对照检查

经验总结

400ms 防抖+Timer 的写法我摘出来跑过:快速输入只触发最后一次,断言通过。但这篇最有价值的是第二句——防抖只解决”何时发请求”,不解决”旧响应晚到”。查询 A 先发后到、查询 B 后发先到,A 覆盖 B 的结果,用户看到的是旧词的结果,这个 bug 在弱网下必现。修法和定位篇一样:每次查询递增 requestId,响应回来只接受最新编号。日志里记”发起时用的关键词”比只看列表更容易定位乱序,但别把用户输入的地址原文打进日志,隐私合规会找麻烦。

小结

防抖减少短时间内重复请求,requestId 或取消令牌解决响应乱序,资源释放则处理页面生命周期。三个问题相关,但各有独立职责,不能只加一个 Timer 就认为搜索竞态已经消失。


分享这篇文章:


相关文章

上一篇
Flutter 项目案例(八):第三方支付回调与订单状态
下一篇
Flutter 项目案例(十一):退款申请、进度与协商记录