简体   繁体   English

RxJS。 组合发射时间小于 1 秒的可观察对象

[英]RxJS. Combine observables that emit less then 1 second apart

There are two observables that may be emiting together or separately: stream1 and stream2 .有两个 observable 可以一起或单独发射: stream1stream2 I need my subscription to fire only if stream2 fires less then 1 second after stream1 does.仅当stream2stream1之后 1 秒内触发时,我才需要触发订阅。
Any way to achieve that with RxJS?有什么方法可以通过 RxJS 实现这一目标?

You can use a timestamp and withLatestFrom to decide which values to emit Here I just filter such that only values that meet your condition pass through.您可以使用时间戳和withLatestFrom来决定要发出哪些值在这里我只是过滤,以便只有满足您条件的值才能通过。

stream2.pipe(
  timestamp(),
  withLatestFrom(stream1.pipe(
    timestamp(),
    startWith({timestamp: 0, value: null})
  )),
  filter(([s2, s1]) => s2.timestamp - s1.timestamp < 1000),
  map(([s2, s1]) => ({
    stream1: s1.value,
    stream2: s2.value
  }))
);

The following solution really will only work with "hot" Observables because I'm subscribing to the second Observable only after the first one emits:以下解决方案仅适用于“热”的 Observable,因为我仅在第一个 Observable 发出后才订阅第二个 Observable:

const stream1$ = timer(1000);
const stream2$ = timer(800);

stream1$
  .pipe(
    switchMap(val1 => stream2$.pipe(
      timeout(1000),
      catchError(() => EMPTY),
      map(val2 => [val1, val2]),
    ))
  )
  .subscribe(console.log);

timeout() will emit an error when stream2$ doesn't emit in less than 1s and the error is immediatelly caught by catchError and ignored. timeout()将在stream2$在不到1s秒内没有发出错误并且错误立即被catchError捕获并忽略时发出错误。

To use this solution with cold Observables you can turn them into hot.要将此解决方案与冷的 Observable 一起使用,您可以将它们变成热的。

const stream1$ = timer(1000);
const stream2$ = timer(1800);
const stream2$Published = stream2$.pipe(publish()) as ConnectableObservable<any>;
const subscription = stream2$Published.connect();

stream1$
  .pipe(
    switchMap(val1 => stream2$Published.pipe(
      timeout(1000),
      catchError(() => EMPTY),
      map(val2 => [val1, val2]),
    ))
  )
  .subscribe(console.log);

Live demo: https://stackblitz.com/edit/rxjs-mqudah?devtoolsheight=60现场演示: https://stackblitz.com/edit/rxjs-mqudah?devtoolsheight=60

I think this is a rare case where using publish() is actually useful.我认为这是使用publish()实际有用的罕见情况。 Otherwise, a little shorter solution might be like the following that will work with cold Observables as well even though it's not as easy to understand:否则,一个更短的解决方案可能如下所示,它也适用于冷 Observables,即使它不容易理解:

const stream1$ = timer(400);
const stream2$ = timer(1200);

combineLatest([
  stream1$.pipe(timestamp()),
  stream2$.pipe(timestamp()),
]).pipe(
  // Check that stream1$ emited first && stream2$ emited less than 1000ms after stream1$.
  filter(([val1, val2]) => (val1.timestamp < val2.timestamp && (val2.timestamp - val1.timestamp) < 1000)),
  map(([val1, val2]) => [val1.value, val2.value]),
).subscribe(console.log);

Live demo: https://stackblitz.com/edit/rxjs-yfhyyh?devtoolsheight=60现场演示: https://stackblitz.com/edit/rxjs-yfhyyh?devtoolsheight=60

However, it's probably not very obvious what the filter() does from quick glance and has some "cognitive comlexity":).但是,可能不是很明显filter()快速浏览并具有一些“认知复杂性”:)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM