← RxJS · 从 Observable 标准契约,到它解决的那些问题 / 落地:这些问题,用流怎么优雅解决 待审核 7 / 7
applications · 竞态 / 防抖 / 拖拽 / 重试

落地:这些问题,用流怎么优雅解决

前面把 契约operatorflatten 都拆过了。这一页把它们对上真实工程痛点——每个都是一段命令式写法会写得很别扭、而用流几行就说清的场景。

1 · autocomplete:防抖 + 消除请求竞态

输入框每次改动都要查询后端。命令式写法有两个坑:抖动(每敲一个字符都发请求)与竞态(先发的慢请求晚返回,把过期结果盖在新结果上)。流的解法:fromEvent(input)debounceTimedistinctUntilChangedswitchMap(search)fromEvent(input) \to debounceTime \to distinctUntilChanged \to switchMap(search)。下面左右对照 naive(直接发)与 switchMap(取消旧的);故意让越短的词延迟越久,好让竞态现形。

2 · 拖拽:mousedown → switchMap(mousemove 直到 mouseup)

拖拽是三个事件流的组合:一次 mousedown 开启一段 mousemove,直到 mouseup 结束。用 switchMap 把每次按下映射成一条「移动流」,再用 takeUntil(mouseup$) 给它自动收尾——不用手动 add / removeEventListener,也不会漏解绑。在下面方块上按住拖动:

3 · retry:失败后按退避延迟重订阅

Observable 的可取消 / 可重订阅让重试变得直接:出错时不必手写循环与计时器,retry({ count, delay }) 会在 error 后延迟一段再重新订阅上游——延迟逐次加倍即指数退避。下面这个请求前两次失败、第三次成功:

4 · 问题 → operator 速查

要解决的问题 operator 组合
输入抖动:每敲一下都发请求 debounceTime / auditTime / throttleTime
重复值:内容没变也重复请求 distinctUntilChanged
请求竞态:过期响应盖掉新结果 switchMap
并行任务收集全部结果 mergeMap + toArray / forkJoin
严格按序处理 concatMap
防连点:提交中忽略新点击 exhaustMap
事件的生命周期 / 解绑 takeUntil / take / takeWhile
失败自动重试 + 退避 retry({ count, delay }) / retryWhen
共享一次请求给多个订阅者 share / shareReplay

这些场景的共同点:「随时间到来的事件」被当成一条可组合、可取消的流。抖动用 debounceTime 合并、竞态用 switchMap 取消、生命周期用 takeUntil 收尾、失败用 retry 重订阅——全都建立在 最初那个契约的三个能力(惰性、多值、可取消)之上。这就是 RxJS 真正解决的问题。