日常做页面开发,列表切换、筛选、tab切换、搜索刷新,都会发送异步接口请求。平时网络稳定、操作平缓,页面展示完全正常。一旦用户快速点击、频繁切换筛选条件,就会偶尔出现数据错乱、内容闪烁、新旧数据叠加的情况。
很多人会下意识归因为网络卡顿、后端数据问题,很少有人意识到,这是前端异步请求竞态引发的渲染bug。
前端发起网络请求是异步的,不会阻塞页面操作。快速连续触发多次查询,就会同时存在多个pending状态的请求。网络环境不确定的情况下,后发起的请求有可能先返回结果,先发起的请求反而滞后返回。
页面只会无脑接收最新返回的数据并赋值渲染,最后到达的旧数据,会覆盖正确的新数据,造成展示错乱。
这个问题特别隐蔽。本地局域网网络速度快、延迟极低,请求顺序基本不会乱,完全复现不了。只有在线上弱网、波动网络、用户高频操作的场景下才会频繁暴露。
我之前做后台筛选列表就遇到过这个问题。用户连续切换两个筛选条件,页面偶尔展示上一个条件的数据,来回切换偶尔正常偶尔错乱,没有固定规律。
排查接口返回数据发现,后端接口本身没有问题,所有请求返回的结果都是对应条件的正确数据,只是返回顺序颠倒了。
多数前端写法都是拿到响应数据直接赋值更新视图,没有任何请求拦截和终止逻辑。先发起的慢请求,滞后执行完成,直接覆盖了后一次的正确渲染结果。
还有一个高频场景是输入框防抖搜索。
用户连续输入关键词,每一次输入都会触发接口请求。即便加了防抖延时,只能减少请求次数,无法彻底杜绝竞态问题。极端情况下,最后一次输入的请求率先返回,之前的延时请求后续抵达,依旧会篡改页面数据。
新手很容易陷入误区,觉得加了防抖就彻底解决了请求紊乱问题,实际上只是降低了bug出现的概率,问题根源依旧存在。
tab频繁切换的场景问题更严重。
不同tab对应不同的接口数据,快速来回切换,多个tab的请求并行执行。任意一个请求滞后返回,就会把当前tab的内容替换成别的tab数据,页面展示完全混乱。
这类bug不会报错,不影响功能使用,只是展示异常,用户刷新页面后立刻恢复正常,所以长期以来都不会被重视,堆积在项目中。
很多项目迭代多年,一直存在偶尔列表错乱、数据闪烁的小问题,本质都是没有处理异步请求的竞态冲突。
解决这个问题并不复杂,核心就是控制请求的有效性。
每次发起新请求前,终止上一个未完成的pending请求,或者通过标记位记录最新请求的标识,只渲染最新请求的结果,忽略所有历史滞后响应。简单的拦截逻辑,就能彻底杜绝多年的偶发渲染错乱问题。
做前端开发越久越明白,页面大部分玄学偶现问题,不是框架bug也不是后端问题,而是异步逻辑处理不严谨。看似不起眼的网络时序问题,恰恰是页面稳定性的关键。