如何替换RxJS中的debounceTime(0)实现按需触发避免流重复执行?
问题原因
combineLatest 会在任意一个源 Observable 发射值时,用所有源的最新值组合触发新发射。onData2 中同步调用两次 next 就会触发两次流执行,debounceTime(0) 本质是把同步阶段的多次发射合并为微任务阶段的一次执行,只是语义不够明确。
方案1:合并关联状态到单一 Subject(最高可读性)
把存在关联的 items 和 size 合并为同一个状态对象存储,无论修改多少个字段,只需要调用一次 next,从根源避免多次触发:
import { BehaviorSubject } from 'rxjs' import { map } from 'rxjs/operators' // 合并关联状态到同一个Subject const state$ = new BehaviorSubject({ items: [], size: 10 }); const visibleItems$ = state$.pipe( map(({ items, size }) => items.slice(0, size)) ); // 仅更新items const onData = bigArr => { state$.next({ ...state$.value, items: bigArr }); } // 仅更新size const changeSize = () => { state$.next({ ...state$.value, size: 20 }); } // 同时更新两个字段,仅触发一次发射 const onData2 = bigArr => { state$.next({ items: bigArr, size: 10 }); }
该方案没有任何黑魔法,逻辑完全显性,对所有开发者都友好。
方案2:封装语义化自定义操作符(不改现有状态结构)
如果你不想调整现有状态拆分的结构,可以把 debounceTime(0) 封装为语义明确的自定义操作符,一眼就能看懂作用:
import { BehaviorSubject, combineLatest, MonoTypeOperatorFunction } from 'rxjs' import { map, debounceTime } from 'rxjs/operators' // 自定义操作符:合并当前同步任务内的所有发射,仅保留最后一次执行 function mergeSyncEmit<T>(): MonoTypeOperatorFunction<T> { return debounceTime(0); } const items$ = new BehaviorSubject([]); const size$ = new BehaviorSubject(10); const visibleItems$ = combineLatest([items$, size$]) .pipe( mergeSyncEmit(), // 语义清晰,不会出现看不懂的0毫秒防抖 map(([items, size]) => items.slice(0, size)) ); // 原有业务逻辑完全不用改动 const onData = bigArr => { items$.next(bigArr); } const changeSize = () => { size$.next(20); } const onData2 = bigArr => { items$.next(bigArr); size$.next(10); }
内容的提问来源于stack exchange,提问作者Gabriel Martins
相关产品推荐
相关产品推荐

