angular - 为什么第二次订阅会改变我的直播结果?

标签 angular typescript rxjs rxjs6

以下代码按预期工作(参见输出):

import { Observable, Subject } from "rxjs";
import { scan } from "rxjs/operators";
export type ColumnFilter = { field: string, value: string };

let sub$: Subject<ColumnFilter> = new Subject<ColumnFilter>();
let obs$: Observable<ColumnFilter[]> = new Observable<ColumnFilter[]>();

obs$ = sub$.pipe(
    scan((acc: ColumnFilter[], curr) => {
        const index = acc.findIndex(f => f.field === curr.field);
        if (index === -1) {
            acc.push({ field: curr.field, value: curr.value });
            return acc;
        }

        curr.value === '' ?
            acc.splice(index, 1) :
            acc[index] = { field: curr.field, value: curr.value };
        return acc;
    }, [])
);


obs$.subscribe(
    value => console.log(value)
);

sub$.next({ field: 'size', value: 'xl' })
sub$.next({ field: 'color', value: 'black' })
sub$.next({ field: 'color', value: '' })


// output:
//    [ { field: 'size', value: 'xl' } ]
//    [ { field: 'size', value: 'xl' }, { field: 'color', value: 'black' } ]
//    [ { field: 'size', value: 'xl' } ]

现在,如果我向 obs$ 可观察对象添加第二个订阅,输出会发生变化:(检查流的最后一个值。它现在包含 { field: 'color', value : '' })

import { Observable, Subject } from "rxjs";
import { scan } from "rxjs/operators";
export type ColumnFilter = { field: string, value: string };


let sub$: Subject<ColumnFilter> = new Subject<ColumnFilter>();
let obs$: Observable<ColumnFilter[]> = new Observable<ColumnFilter[]>();

obs$ = sub$.pipe(
    scan((acc: ColumnFilter[], curr) => {
        const index = acc.findIndex(f => f.field === curr.field);
        if (index === -1) {
            acc.push({ field: curr.field, value: curr.value });
            return acc;
        }

        curr.value === '' ?
            acc.splice(index, 1) :
            acc[index] = { field: curr.field, value: curr.value };
        return acc;
    }, [])
);

// vvv this was added
obs$.subscribe()
// ^^^ this was added

obs$.subscribe(
    value => console.log(value)
);

sub$.next({ field: 'size', value: 'xl' })
sub$.next({ field: 'color', value: 'black' })
sub$.next({ field: 'color', value: '' })

// output:
//    [ { field: 'size', value: 'xl' } ]
//    [ { field: 'size', value: 'xl' }, { field: 'color', value: 'black' } ]
//    [ { field: 'size', value: 'xl' }, { field: 'color', value: '' } ]

我不明白为什么第二个订阅会改变流的结果。我只能猜测这与改变累加器有关?因为如果我使用 acc.filter 而不是 acc.splice,它会按预期工作。

编辑

添加了堆栈 Blitz :https://stackblitz.com/edit/rxjs-6-opeartors-uzojgw?file=index.ts

最佳答案

以下是第二个示例代码中发生的情况:当 sub$.next() 触发事件时,管道会针对每个订阅的可观察量执行一次。由于 scan 运算符的 acc: ColumnFilter[] 在这些执行之间共享,因此会发生所描述的副作用。

我的建议是使用 shareshareReplay 运算符,以便每个事件仅执行一次管道,并且为订阅者多播管道发出的值(= 所有订阅者都获得相同的对象引用)。​​

obs$ = sub$.pipe(
  scan((acc: ColumnFilter[], curr) => {
    const index = acc.findIndex((f) => f.field === curr.field);
    if (index === -1) {
      acc.push({ field: curr.field, value: curr.value });
      return acc;
    }

    curr.value === ''
      ? acc.splice(index, 1)
      : (acc[index] = { field: curr.field, value: curr.value });
    return acc;
  }, []),
  share() // you might use shareReplay(1) instead, e.g. if you have late subscribers
);

关于angular - 为什么第二次订阅会改变我的直播结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73754343/

相关文章:

html - 字段对齐未按预期工作

angular - webpack 源映射缺少名称部分

reactjs - 未定义(未定义,未定义): Cannot find type definition file for 'src' . TS2688 中的 typescript 错误

typescript - 类型声明在不丢失名称的情况下删除类型周围的 "Array"

javascript - Ngx-Bootstrap Typeahead 在输入清除时保留下拉值

javascript - 清除每个函数调用的超时 Angular2 RxJS

javascript - Angular 嵌套类别和 *ngFor 循环

javascript - 对后端的调用在服务内部可以正常工作,但在服务外部则不行

javascript - 为什么 Record<string, any> 可以等于 Functions?

ios - 是否可以使用 RxSwift 在输入字段数组上执行自定义 Binder ?