RxJS - 管道 observable re-运行 过于频繁

RxJS - Piped observable re-running too often

单击按钮后,我想切换到我的 file$ observable,检查它是否已填充,并使用它上传 uploadRates(file, date) 中的文件。

const click$ = Observable.fromEvent(this.uploadButton.nativeElement, 'click').pipe(
    switchMapTo(this.file$),
    filter(file => !!file && !!this.dateForRates),
    tap(_ => this.isLoading$.next(true)),
    exhaustMap(file => this.uploadRates(file, this.dateForRates))
).subscribe({
    next: x => {
        this.handleUploadRatesResult(x);
        this.isLoading$.next(false);
    },
    complete: () => {
        console.log('complete');
        this.isLoading$.next(false);
    },
    error: err => {
        console.log(err);
        this.isLoading$.next(false);
    }
});

它有效,但我只是不想在代码中的其他地方执行类似 this.file$.next(undefined); 的操作时重新 运行 任何管道,它确实如此。单击按钮时,我只希望它为 运行。如何使 ngOnInit 中的管道仅在单击按钮时重新 运行,但仍然从我的 file$ 变量中提取文件以检查它是否已填充并在单击时上传按钮?

我认为问题是 file$ 在发出一个值后没有完成。这意味着内部订阅将保持活动状态。

你可以做的是添加一个 take(1) 以确保它在第一个发出的值之后不再被订阅:

switchMapTo(this.file$.pipe(take(1))),

您也可以使用 withLatestFrom 运算符。它将订阅给定的可观察值并存储最新值,但如果可观察值本身发出则不会发出:

const click$ = Observable.fromEvent(this.uploadButton.nativeElement, 'click').pipe(
    withLatestFrom(this.file$),
    map(([_, file]) => file),
    filter(file => !!file && !!this.dateForRates),
    tap(_ => this.isLoading$.next(true)),
    exhaustMap(file => this.uploadRates(file, this.dateForRates))
).subscribe({
    next: x => {
        this.handleUploadRatesResult(x);
        this.isLoading$.next(false);
    },
    complete: () => {
        console.log('complete');
        this.isLoading$.next(false);
    },
    error: err => {
        console.log(err);
        this.isLoading$.next(false);
    }
});

我通常不会容忍使用 RxJS BehaviorSubjects value getter。它可用于同步获取可观察对象持有的当前值。但在这种情况下,可以利用它来避免订阅可观察对象。尝试以下

const click$ = Observable.fromEvent(this.uploadButton.nativeElement, 'click').pipe(
    map(() => this.file$.value),       // <-- use the `value` getter here
    filter(file => !!file && !!this.dateForRates),
    tap(_ => this.isLoading$.next(true)),
    exhaustMap(file => this.uploadRates(file, this.dateForRates))
).subscribe({
  ...