首页 > 解决方案 > RxJS 中点击运算符的输出问题

问题描述

我对以下代码的输出感到困惑,根据 take(3) 处理应该在渲染 10 后停止,但仍然从点击运算符获得 5,6 和 9。请参考下面的输出和代码片段。

of(null, 20, 15, 10, 5, 6, 9)
      .pipe(
        tap(val => console.log(`Tapped value ${val}`)),
        filterNil(),
        take(3)
      )
      .subscribe(
        item => console.log(`Rendering Item ${item}`),
        err => console.log(err),
        () => console.log('Completed')
      );
  }

const filterNil = () => (source: Observable<any>) =>
  new Observable(observer => {
    return source.subscribe({
      next(value) {
        if (value !== undefined && value !== null) {
          observer.next(value);
        }
      },
      error(error) {
        observer.error(error);
      },
      complete() {
        observer.complete();
      }
    });
  });

标签: typescriptrxjs

解决方案


这个问题的最终答案

以下帖子提供了此问题的正确答案。

我的第一个答案 - 一个简单的答案

您所看到的取决于您的代码是完全同步的事实,因此unsubscribe隐含在 3 中的后 3 次发射take(3)没有机会运行。

看看这个版本

of(null, 20, 15, 10, 5, 6, 9)
      .pipe(
        delay(0),  // >>> intruduce a delay
        tap(val => console.log(`Tapped value ${val}`)),
        filterNil(),
        take(3)
  )

在这里,您介绍了 a delay,它提供take了可能性unsubscribe,因此,您看到了您期望的行为。

不是答案,而是更详细的推理

我对这个问题进行了更多调查,并且发现了一些使我之前的答案过于简单的事情。

让我们从filterNil()一个合法的自定义运算符开始,它应该与 执行相同的操作filter(item => item !== null),其中filter一个运算符由 提供rxjs/operators,即由库提供。

现在,如果我们替换filter(item => item !== null)filterNil()pipe我们会得到不同的结果

of(null, 20, 15, 10, 5, 6, 9)
      .pipe(
        tap(val => console.log(`Tapped value ${val}`)),
        filter(item => item !== null),
        take(3)
      )

      .subscribe(
        item => console.log(`Rendering Item ${item}`),
        err => console.log(err),
        () => console.log('Completed')
      );
  }

// the output on the console is

Tapped value null
Tapped value 20
Rendering Item 20
Tapped value 15
Rendering Item 15
Tapped value 10
Rendering Item 10
Completed

这意味着filter(item => item !== null)filterNil()不等价。

它们不等价的事实似乎来自与和的某种不同性质的联合subscribe方法的实现。ObservablefilterNilfilter

使用时, Observable方法filterNil的执行痕迹是这样的subscribe

在此处输入图像描述

另一方面,如果我们使用运算符,则Observable 方法 filter的执行轨迹是这样的subscribe在此处输入图像描述

因此,filterNil确实将operator属性设置为 null 而filter确实将operator属性设置为这一事实FilterOperator似乎驱动了不同的行为。背后的原因我不清楚,值得提出一个新问题。


推荐阅读