Javascript observables:需要switchMap的功能,但略有不同

时间:2017-05-05 15:32:47

标签: javascript rxjs observable

我在下面的代码中有一个Rxjs observable(stream),它发出了可观察量(subjOnesubjTwo)。每个内部可观察量可以在任何时间以任何顺序发出它们自己的值。我的任务是从subjOne捕获值,直到subjTwo发出它的第一个值。

const subjOne = new Subject();
const subjTwo = new Subject();

const stream = Observable.create(observer => {
    observer.next(subjOne);
    observer.next(subjTwo);
});

stream
    .someOperator(subj => subj)
    .subscribe(value => console.log('Value: ', value));

示例1: subjOne发出值1和2,然后subjTwo发出值3,然后subjOne发出4。 输出应为:1,2,3。

示例2: subjTwo发出1,然后subjOne发出2。 输出应为1。

switchMap不适合此处,因为只要从subjOne发出subjTwo,它就会从stream中删除值。关于如何实现这一点的任何想法?感谢。

更新:在我的实际案例中,不仅有两个内部可观察对象 - subjOnesubjTwo - 而且是一个恒定的流,因此需要手动编码{{ 1}}不是一个可行的选择。

3 个答案:

答案 0 :(得分:3)

我认为这可以满足您的需求:

// scan to let us keep combining the previous observable
// with the next observable
source
  .scan((current, next) => {
    // takeUntil to stop current when next produces
    const currentUntil = current.takeUntil(next);
    // now merge current with next
    return currentUntil.merge(next)
  }, Rx.Observable.empty())
  // switch to the most recent version of the combined inner observables
  .switch();

请注意,只有内部可观察对象 hot 时,这才能正常工作。如果它们是冷可观察的,则需要更多代码才能实现。

答案 1 :(得分:0)

听起来你正在寻找takeUntil

takeUntil侦听一个流,直到第二个流发出。所以对于你的例子

// Emits every second
const source = Observable.timer(0, 1000);

// Emits once after 3 seconds
const canceller = Observable.timer(3000);

source
  // Takes from the source until this stream emits
  .takeUntil(canceller)
  .subscribe({
    next: x => console.log(`Value ${x}`),
    complete: () => console.log('Done')
  });
// Value 0 -> 0 seconds
// Value 1 -> 1 seconds
// Value 2 -> 2 seconds
// Done -> 3 seconds

答案 2 :(得分:0)

您可以将两个主题分开,然后将它们与takeUntil

结合使用
const subjOne = new Subject();
const subjTwo = new Subject();

const stream = Observable.create(observer => {
    observer.next(subjOne);
    observer.next(subjTwo);
});

const first$ = stream.take(1).flatMap(x=>x)
const second$ = stream.skip(1).take(1).flatMap(x=>x)

first$.takeUntil(second$).subscribe(...)