当前位置: 首页 > news >正文

ArkTS 搜索旧请求覆盖新结果怎么办:中式美食输入框怎么防止慢请求回写

ArkTS 搜索旧请求覆盖新结果怎么办:中式美食输入框怎么防止慢请求回写

中式美食的搜索框不是等用户输入完才有动作。用户可能连续输入“番”“番茄”“番茄炒蛋”,也可能一边删一边改。如果每次输入都发一次查询,旧请求不一定先回来。最常见的现象是:输入框已经是“番茄炒蛋”,列表却显示“番”的结果。

这个问题不要只靠防抖。防抖能减少请求次数,但不能保证慢请求不会最后回来。我的做法是加一个requestVersion,每次发请求都带版本号,只有最新版本能回写页面。

本文导读

问题处理方式
快速输入后结果乱跳每次搜索递增 requestVersion
慢请求覆盖新结果回写前比较版本号
清空输入框仍显示旧结果清空时也递增版本并回到默认列表
搜索失败后页面乱保留关键词,单独显示错误态

环境和文件边界

项目内容
开发工具DevEco Studio
HarmonyOS SDKAPI 12,Stage 模型
搜索页entry/src/main/ets/features/search/SearchPage.ets
状态层entry/src/main/ets/features/search/SearchViewModel.ets
数据层entry/src/main/ets/data/repository/RecipeSearchRepository.ets
本文重点ArkTS 搜索请求时序、旧请求拦截、RDB 查询

错误写法:谁回来晚谁覆盖

asynconKeywordChange(keyword:string):Promise<void>{this.keyword=keywordthis.loading=truethis.result=awaitthis.repository.search(keyword)this.loading=false}

这段代码最大的问题是没有判断“这个结果是不是当前输入框想要的结果”。请求 A 搜“番”,请求 B 搜“番茄炒蛋”。如果 B 先回来,页面显示正确;A 后回来,又把列表覆盖成旧结果。

用 requestVersion 拦住旧回写

exportclassSearchViewModel{privaterequestVersion:number=0keyword:string=''loading:boolean=falseerrorText:string=''result:RecipeCard[]=[]asyncsearch(keyword:string):Promise<void>{constversion=++this.requestVersionthis.keyword=keywordthis.loading=truethis.errorText=''try{constrows=awaitthis.repository.searchRecipe(keyword)if(version!==this.requestVersion)returnthis.result=rows}finally{if(version===this.requestVersion){this.loading=false}}}}

这个版本号不是为了炫技,就是一个很朴素的判断:你回来时,如果已经不是最新请求,就不要改页面。

清空输入框也要当成一次新请求

asyncclearKeyword():Promise<void>{constversion=++this.requestVersionthis.keyword=''this.errorText=''this.loading=falsethis.result=awaitthis.repository.queryDefaultRecommend()if(version!==this.requestVersion){return}}

清空输入框容易被忽略。用户点清空后,旧搜索请求如果还在路上,回来以后会把默认推荐覆盖掉。所以清空也要递增版本。

Repository 只负责查,不负责决定能不能回写

exportclassRecipeSearchRepository{asyncsearchRecipe(keyword:string):Promise<RecipeCard[]>{constkey=keyword.trim()constpredicates=newrelationalStore.RdbPredicates('recipe')predicates.like('search_text',`%${key}%`)predicates.orderByDesc('score')predicates.orderByDesc('updated_at')predicates.limitAs(30)constrows=awaitthis.queryRows(predicates)returnrows.map(row=>this.toRecipeCard(row))}}

Repository 不需要知道输入框现在是什么。它只负责把某个关键词查出来。能不能回写,是 ViewModel 的职责。

页面层只绑定状态

@Componentexportstruct SearchPage{@StateviewModel:SearchViewModel=newSearchViewModel()build(){Column(){SearchInput({value:this.viewModel.keyword,onChange:(value:string)=>this.viewModel.search(value),onClear:()=>this.viewModel.clearKeyword()})SearchResultList({loading:this.viewModel.loading,errorText:this.viewModel.errorText,recipes:this.viewModel.result})}}}

页面层不要再自己判断旧请求。它只要把输入动作交给 ViewModel,然后根据 ViewModel 状态渲染。

防抖可以加,但不是唯一防线

exportclassSearchDebouncer{privatetimer:number=0run(task:()=>void,delay:number=250):void{if(this.timer>0){clearTimeout(this.timer)}this.timer=setTimeout(task,delay)}}

防抖的作用是少发请求,requestVersion的作用是防止旧请求回写。两个解决的是不同问题,不要把它们混成一个。

回归验收记录

步骤操作预期
1快速输入“番”“番茄”“番茄炒蛋”最终只显示最后一个关键词结果
2人为延迟第一个请求旧请求返回后不能覆盖新列表
3清空输入框回到默认推荐,不保留旧搜索结果
4搜索失败保留关键词和错误态,不乱写空结果
5切换分类再搜索requestVersion 重新生效
6返回搜索页输入框和结果保持一致

排查顺序

顺序先看什么为什么先看它
1请求返回前有没有版本判断没有判断就会被旧请求覆盖
2清空输入是否递增版本清空也可能被旧请求回写
3loading 是否按版本关闭旧请求不能把新请求的 loading 关掉
4防抖和版本号是否同时存在防抖减少请求,版本号保证正确

边界责任

层级应该负责什么不应该负责什么
SearchPage绑定输入框和结果列表判断哪个请求有效
SearchViewModel维护 requestVersion 和页面状态拼复杂 SQL
Repository根据关键词查 RDB决定是否回写页面
Debouncer减少输入触发频率替代请求版本判断

小结

搜索页最怕的是“输入框和结果不一致”。用户看到这种错乱,会直接怀疑搜索功能不可信。

中式美食这里我会把时序控制放在 ViewModel:输入变化递增版本,请求返回前比较版本,清空输入也递增版本。Repository 只查数据,页面只渲染状态。这样即使网络慢、用户输入快,旧请求也不能把新结果覆盖掉。

http://www.cnnetsun.cn/news/3346150.html

相关文章:

  • 3 种混合波束成形方案对比:传统优化 vs 深度学习 vs 深度强化学习
  • Realtek RTL8821CU Linux驱动终极指南:三步解决无线网卡兼容性问题
  • 革命性AI空气动力学工具XMeshGraphNet DrivAerML:NVIDIA如何用图神经网络加速汽车设计
  • Lumino部署与打包:从开发到生产的完整工作流程
  • JavaString知识梳理
  • C# Task WaitAll、WaitAny、WhenAll、WhenAny
  • nabla.nvim插件开发指南:如何为项目贡献新的数学符号支持
  • NLP核心技术实践之(四)命名实体识别与关系抽取的端到端应用
  • 革命性AI视频生成工具AnyFlow-FAR-Wan2.1-1.3B-Diffusers:NVIDIA推出的任意步数视频扩散模型完全指南
  • SGM 代价聚合:4路径与8路径性能对比,P1/P2惩罚项调参实战
  • 让qoder操作doc的步骤
  • AI+港口智慧物流:集装箱调度+船舶预测+堆场优化
  • 如何在AMD NPU上部署Llama-2-7b-hf_rai_1.7.1_npu_4K:完整新手教程
  • AI+危险品运输:全程监控+应急响应+合规管理
  • AI+供应链韧性:风险预测+应急调度+弹性优化
  • gemma-4-e4b-it-OptiQ-4bit的部署优化:内存管理、批处理和性能调优最佳实践
  • 21天学pcie--Linux 下查看 BAR:lspci -vv(实战必会)
  • ChatGPT生成抖音脚本不火?问题不在模型,在于你漏掉了这4个关键元数据注入节点
  • 终极指南:如何免费解锁Wand-Enhancer的所有高级游戏修改功能
  • 一个爬虫项目改成 AI 流程后,最难的部分完全变了
  • 如何快速上手AnyFlow-FAR-Wan2.1-1.3B-Diffusers:5分钟搭建文本到视频生成环境
  • RoCEv2 网络的完整协议栈简介
  • Qwen2.5-7B-Instruct_rai_1.7.1_npu_4K:AMD Ryzen AI上的高效大语言模型部署指南
  • 如何用Gotalk实现分布式系统负载均衡:心跳机制详解
  • NVIDIA-Nemotron-3-Nano-4B-OptiQ-4bit:Apple Silicon专属的革命性混合架构大模型来了!
  • 从投诉率骤升23%到NPS提升18分,我们如何用反馈聚类+情感时序建模重构产品决策链,
  • 别再写for循环了:2024最前沿的向量化AI分析法——用PyTorch+Polars实现毫秒级特征生成(含GPU加速实测对比数据)
  • 解密Enigma虚拟打包文件:evbunpack实战指南
  • 【技术实践】上海交通大学学位论文本地化保存与自动化抓取方案解析
  • AI绘图实战:蜡笔风个人主页海报提示词拆解