【问题标题】:Rxjs operator similar to combineLatest but that trigger if only one emitRxjs 操作符类似于 combineLatest 但如果只有一个发出就会触发
【发布时间】:2021-10-09 14:45:25
【问题描述】:

combineLatest的RxJs doc中,写着:

请注意,combineLatest 不会发出初始值,直到每个 observable 至少发出一个值。

是否有一个像combineLatest 一样工作的运算符,但即使只有一个可观察对象发出一个值,它也会发出一个值?

【问题讨论】:

  • 我认为您正在寻找 withLatestFrom。
  • 你可能会寻找merge。但它只发出发出的值,而不是来自其他可观察对象的值。另一种方法:您可以通过管道将combineLatest 的每个可观察对象通过startWith 发出初始值。
  • @Mrk Sef 的答案在我看来几乎是合法的,但要付出引入潜在的 null 值的成本。你问这个问题的根本原因是什么?在我看来,它可能会以更优雅的方式解决。

标签: typescript rxjs


【解决方案1】:

假设observables 是一个可观察的数组

combineLatest(...observables.map(
  s => s.pipe(
    startWith(null)
  )
)).pipe(
  filter(arr => arr.filter(x => x != null).length > 0)
)

这将在源 observable 尚未发出的任何位置发出一个带有 null 的数组。它还会过滤掉整个数组为空的第一个发射。


根据评论更新:

同样的事情,但可能更健壮一些,因为它允许具有开发人员知道的形状的虚拟值。

你可以用任何东西替换'null'。例如:

combineLatest(...observables.map(
  s => s.pipe(
    startWith({dummy: true})
  )
)).pipe(
  filter(arr => arr.filter(x => !x?.dummy).length > 0)
)

更新以提高性能:

在规模上,循环遍历数组以查看是否所有值都是 void/dummy 值对性能不利。因为(在这种情况下)我们只想忽略第一次发射,所以这个自定义操作符可以在不检查值的情况下做到这一点。

filterFirst(n) 将忽略第一个 n 发射:

function filterFirst<T>(n: number): MonoTypeOperatorFunction<T>{
  return s => defer(() => {
    let count = 0;
    return s.pipe(
      filter(_ => n <= count++)
    )
  });
}

那么你可以如下使用它:

combineLatest(...observables.map(
  s => s.pipe(
    startWith(null)
  )
)).pipe(
  filterFirst(1)
)

【讨论】:

  • 唯一的(小)问题可能是[null, ..., null] 是否是一个合适的值。在一般情况下使用唯一的符号/引用会更安全。
  • 显然!正是我想要的
  • @arturgrzesiak 我进行了第二次更新,我认为它符合一般情况,也应该更快。
猜你喜欢
  • 2017-04-08
  • 1970-01-01
  • 2021-12-22
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多