Angular RxJS中observable添加timer延迟后返回数据不全问题
问题根因
combineLatest传参写法错误,导致拿到的结果结构不符合预期。combineLatest支持两种传参方式:
- 传入单个参数:元素为Observable的数组,输出结果为每个Observable最新值组成的数组,长度和输入的Observable数组长度一致
- 传入多个参数:每个参数为独立Observable,输出结果为所有参数Observable最新值组成的数组,长度和传入的Observable参数个数一致
你的代码中传入了两个参数:第一个是17个列显隐判断逻辑组成的普通数组(不是Observable),第二个是timer(500)。combineLatest会自动将非Observable类型的入参通过of()转为即时发射值的流,因此实际参与合并的只有2个流:
- 第一个流直接发射你传入的17个显隐逻辑组成的数组
- 第二个流500ms后发射数值0
最终map中拿到的showCols是长度为2的数组:[17个列显隐布尔值组成的数组, 0],而非你预期的17个布尔值组成的数组。
后续过滤列时,索引i=0取到的是整个显隐布尔数组(为truthy,第一列保留),i>=1时取到的是0或undefined(均为falsy,其余列全被过滤),最后追加edit列,就得到了你看到的长度为2的返回结果。
修复方案
如果你的需求是等所有列显隐判断完成后,延迟500ms再返回结果,不需要把timer混入合并流,直接使用delay操作符即可,逻辑更简洁也不会出现传参错误:
this.displayedColumns = combineLatest( this.table.columns.reduce((observables: Observable<boolean>[], col) => { // 处理列的showIf属性 const show = col.showIf(this.injector, this.route.queryParamMap); observables.push(show instanceof Observable ? show : of(show)); return observables; }, []) ).pipe( delay(500), map(showCols => { const cols = this.table.columns.filter((c, i) => showCols[i]) .map(c => c.id); this.editEnabled && cols.push('edit'); this.deleteEnabled && cols.push('delete'); console.log('cols', cols) return cols; }) );
如果你确实要通过合并timer的方式实现延迟,需要把timer放入Observable数组中,再整体传给combineLatest,注意最后要剔除timer发射的多余值:
this.displayedColumns = combineLatest([ ...this.table.columns.reduce((observables: Observable<boolean>[], col) => { const show = col.showIf(this.injector, this.route.queryParamMap); observables.push(show instanceof Observable ? show : of(show)); return observables; }, []), timer(500) ]).pipe( map(resArr => { // 去掉最后一位timer发射的0,取前面的列显隐结果 const showCols = resArr.slice(0, -1); const cols = this.table.columns.filter((c, i) => showCols[i]) .map(c => c.id); this.editEnabled && cols.push('edit'); this.deleteEnabled && cols.push('delete'); console.log('cols', cols) return cols; }) );
内容的提问来源于stack exchange,提问作者Cluadia Hedda
相关产品推荐
相关产品推荐

