【问题标题】:How should I emit a single value when observable completes?当 observable 完成时,我应该如何发出单个值?
【发布时间】:2021-05-01 13:50:32
【问题描述】:

我想在原始 observable 完成时发出一个值,让我们说如下,使用假想运算符 mapComplete

let arr = ['a','b', 'c'];

from(arr)
.pipe(mapComplete(()=>'myValue'))
.pipe(map((v)=>`further processed: ${v}`))
.subscribe(console.log)
//further processed: myValue

我尝试了以下方法,但似乎不合适:

1.

from(arr)
.pipe(toArray())
.pipe(map(()=>'myValue'))
.pipe(map((v)=>`further processed: ${v}`))
.subscribe(console.log);
//further processed: myValue

问题:如果原始 observable 是一个巨大的流,我不想将它缓冲到一个数组中,只是为了发出一个值。

2.

from(arr)
.pipe(last())
.pipe(map(()=>'myValue'))
.pipe(map((v)=>`further processed: ${v}`))
.subscribe(console.log);
//further processed: myValue

问题:如果流完成但没有发出任何内容,我会收到错误:[Error [EmptyError]: no elements in sequence]

执行上述操作的正确方法是什么(以 rxjs 而言)?

【问题讨论】:

    标签: rxjs observable rxjs6


    【解决方案1】:

    您可以通过构建自己的自定义运算符来实现您想要的。

    代码可能如下所示

    const emitWhenComplete = <T>(val: T) => <U>(source: Observable<U>) =>
      new Observable<T>((observer) => {
        return source.subscribe({
          error: (err) => observer.error(err),
          complete: () => {
            observer.next(val);
            observer.complete();
          },
        });
      });
    

    基本上这个操作符会接受源 observable,忽略它发出的所有值,并且只在源完成时发出。

    您可以查看this stackblitz 进行一些测试。

    【讨论】:

      【解决方案2】:

      您可以使用ignoreElements 来实现此目的,不发出任何东西,endWith 在完成时发出一个值。

      from(arr).pipe(
        ignoreElements(),
        endWith('myValue'),
        map(v => `further processed: ${v}`)
      ).subscribe(console.log);
      

      如果你想在map 中执行一个函数,你可以预先使用count() 在完成时发出一个值(发出的值的数量)。

      from(arr).pipe(
        count(), // could also use "reduce(() => null, 0)" or "last(null, 0)" or "takeLast(1), defaultIfEmpty(0)" 
        map(() => getMyValue()),
        map(v => `further processed: ${v}`)
      ).subscribe(console.log);
      

      【讨论】:

      • 不错的答案。注意:为了完整起见,由于虚构的mapComplete() 接受一个 lambda,因此最好提供一个在发射时计算值的解决方案。我想一张额外的地图可以解决它,但也许还有其他一些解决方案..
      • @MarinosAn 是的,您可以在endWith 之后使用map。我能想到的唯一另一个更短的选项是countmap 之前。 count 也有一些替代品,但您可以在我的编辑中看到它们都更长。
      • 我想现在答案已经完成了!
      【解决方案3】:

      您还可以使用 last() 运算符和默认值。当流为空时,它将消除no elements in sequence 错误。

      from(arr).pipe(
        last(null, 'myValue'),  // `null` denotes no predicate
        map(_ => 'myValue'),    // map the last value from the stream
        map((v)=>`further processed: ${v}`)
      ).subscribe(console.log);
      

      【讨论】:

      • last(null, 'myValue') 不会发出 myValue 作为最后一个值,如果 from(arr) 发出一些东西。因此,如果from(arr) 发出任何内容,您仍然需要使用map(()=&gt;'myValue') 将其最后一个值映射到myValue
      • @fridoo:很好,我已经编辑了帖子。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-11
      • 1970-01-01
      • 1970-01-01
      • 2020-09-27
      • 1970-01-01
      相关资源
      最近更新 更多