RxJS operator waitUntil

时间:2019-01-18 18:52:08

标签: rxjs

a: 1---2-3-4--5---6
b: ------T---------

o: ------1234-5---6

Using RxJS, is there some operator that can accomplish the diagram above? I have stream A which is a random stream of events, given a stream B which has a single true event, can I have an output stream that doesn't emit anything until that true event, and then sends everything is had saved up until then and afterwards emits normally?

I thought maybe I could use buffer(), but it seems like there is no way to do a one time buffer like this with that operator.

3 个答案:

答案 0 :(得分:1)

const { concat, interval, of, from } = rxjs;
const { share, delay, toArray, takeUntil, mergeMap } = rxjs.operators;

const waitUntil = signal$ => source$ => {
  const sharedSource$ = source$.pipe(share());
  return concat(
    sharedSource$.pipe(
      takeUntil(signal$),
      toArray(),
      mergeMap(from)
    ),
    sharedSource$
  );
}

const stopWaiting$ = of('signal').pipe(delay(2000));

const source$ = interval(500).pipe(
    waitUntil(stopWaiting$)
).subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.js"></script>

答案 1 :(得分:1)

我认为@ZahiC的解决方案是正确的,但就我个人而言,我会使用multicast运算符在单个链中进行操作。

a$.pipe(
  multicast(new Subject(), s => concat(
    s.pipe(
      buffer(b$),
      take(1),
    ),
    s
  )),
)

multicast基本上将流分成两部分,其中concat首先订阅第一个缓冲的对象,直到b$发出为止。然后,由于take(1)concat再次订阅相同的流,但这次没有缓冲,因此它立即完成。

答案 2 :(得分:0)

这是我使用TypeScript的解决方案:

export const queueUntil = <T>(signal$: Observable<any>) => (source$: Observable<T>) => {
    let shouldBuffer = true;

    return source$.pipe(
        bufferWhen(() => shouldBuffer ? signal$.pipe(
            tap(() => shouldBuffer = false),
        ) : source$),
        concatMap(v => v),
    );
};

可以这样使用:

a$.pipe(
    queueUntil(b$)
)