如何在发射之前使一个RxJS Observable序列等待另一个RxJS Observable序列完成?

时间:2015-05-29 01:21:18

标签: javascript observable rxjs

说我有一个Observable,就像这样:

var one = someObservable.take(1);

one.subscribe(function(){ /* do something */ });

然后,我有第二个观察:

var two = someOtherObservable.take(1);

现在,我想订阅two,但我想确保在one订阅者被解雇之前two已完成。我可以在two上使用什么样的缓冲方法让第二个等待第一个缓冲方法完成?

我想我希望暂停two直到one完成。

9 个答案:

答案 0 :(得分:27)

我能想到的几种方式

//Method one
var one = someObservable.take(1);
var two = someOtherObservable.take(1);
one.concat(two).subscribe(function() {/*do something */});

//Method two, if they need to be separate for some reason
var one = someObservable.take(1);
var two = someOtherObservable.take(1).publish();
two.subscribe(function(){/*do something */});
one.subscribe(function(){/*do something */}, null, two.connect.bind(two));

答案 1 :(得分:10)

skipUntil()与last()

skipUntil:忽略发出的项目,直到发出另一个可观察的物体

最后一个:发出序列中的最后一个值(即,等到它完成再发出)

请注意,从observable传递到skipUntil的所有内容都将取消跳过,这就是为什么我们需要添加last()-等待流完成的原因。

main$.skipUntil(sequence2$.pipe(last()))

官方:https://rxjs-dev.firebaseapp.com/api/operators/skipUntil


可能的问题:请注意,last()本身will error(如果什么也没有发出)。 last()运算符的确具有default参数,但仅当与谓词结合使用时。我认为,如果这种情况对您来说是个问题(如果sequence2$可能没有发出就完成了),那么其中一种应该可以工作(当前未经测试):

main$.skipUntil(sequence2$.pipe(defaultIfEmpty(undefined), last()))
main$.skipUntil(sequence2$.pipe(last(), catchError(() => of(undefined))

请注意,undefined是要发出的有效项目,但实际上可以是任何值。另外请注意,这是连接到sequence2$的管道,而不是main$管道。

答案 2 :(得分:8)

如果要确保保留执行顺序,可以使用flatMap作为以下示例

const first = Rx.Observable.of(1).delay(1000).do(i => console.log(i));
const second = Rx.Observable.of(11).delay(500).do(i => console.log(i));
const third = Rx.Observable.of(111).do(i => console.log(i));

first
  .flatMap(() => second)
  .flatMap(() => third)
  .subscribe(()=> console.log('finished'));

结果将是:

"1"
"11"
"111"
"finished"

答案 3 :(得分:7)

这是利用switchMap的结果选择器

的另一种可能性
var one$ = someObservable.take(1);
var two$ = someOtherObservable.take(1);
two$.switchMap(
    /** Wait for first Observable */
    () => one$,
    /** Only return the value we're actually interested in */
    (value2, value1) => value2
  )
  .subscribe((value2) => {
    /* do something */ 
  });

由于switchMap的结果选择器已被折旧,因此这是一个更新版本

const one$ = someObservable.pipe(take(1));
const two$ = someOtherObservable.pipe(
  take(1),
  switchMap(value2 => one$.map(_ => value2))
);
two$.subscribe(value2 => {
  /* do something */ 
});

答案 4 :(得分:2)

这是一个用TypeScript编写的自定义运算符,它在发出结果之前等待信号:

export function waitFor<T>(
    signal$: Observable<any>
) {
    return (source$: Observable<T>) =>
        new Observable<T>(observer => {
            // combineLatest emits the first value only when
            // both source and signal emitted at least once
            combineLatest([
                source$,
                signal$.pipe(
                    first(),
                ),
            ])
                .subscribe(([v]) => observer.next(v));
        });
}

您可以像这样使用它:

two.pipe(waitFor(one))
   .subscribe(value => ...);

答案 5 :(得分:1)

这是另一个,但我感觉更直接和直观(或者至少是自然,如果你已经习惯了承诺),接近。基本上,您使用Observable.create()创建一个Observable来将onetwo包装为单个Observable。这与Promise.all()的工作方式非常相似。

var first = someObservable.take(1);
var second = Observable.create((observer) => {
  return first.subscribe(
    function onNext(value) {
      /* do something with value like: */
      // observer.next(value);
    },
    function onError(error) {
      observer.error(error);
    },
    function onComplete() {
      someOtherObservable.take(1).subscribe(
        function onNext(value) {
          observer.next(value);
        },
        function onError(error) {
          observer.error(error);
        },
        function onComplete() {
          observer.complete();
        }
      );
    }
  );
});

那么,这里发生了什么?首先,我们创建一个新的Observable。传递给Observable.create()的函数,恰当地命名为onSubscription,传递给观察者(根据传递给subscribe()的参数构建),类似于resolve和{{1在创建新Promise时组合成一个对象。这就是我们如何实现神奇的工作。

reject中,我们订阅了第一个Observable(在上面的示例中,这称为onSubscription)。我们如何处理onenext取决于您,但我的示例中提供的默认值通常适用。但是,当我们收到error事件时,表示complete现已完成,我们可以订阅下一个Observable;从而在第一个Observable完成后触发第二个Observable。

为第二个Observable提供的示例观察者非常简单。基本上,one现在的行为与您期望second在OP中的行为一样。更具体地说,two将发出second发出的第一个且唯一的第一个值(因为someOtherObservable)然后完成,假设没有错误。

实施例

如果您希望在现实生活中看到我的示例,可以复制/粘贴以下完整的工作示例:

take(1)

如果您观看控制台,上面的示例将打印:

  

1

     

6

     

完成!

答案 6 :(得分:1)

这是一种可重复使用的方法(它是打字稿,但您可以将其适应js):

export function waitFor<T>(signal: Observable<any>) {
    return (source: Observable<T>) =>
        new Observable<T>(observer =>
            signal.pipe(first())
                .subscribe(_ =>
                    source.subscribe(observer)
                )
        );
}

,您可以像任何运算符一样使用它:

var two = someOtherObservable.pipe(waitFor(one), take(1));

基本上,它是一个运算符,将可观察的源推迟到可观察的信号发出第一个事件之前。

答案 7 :(得分:0)

由于 mergeMap (或他的别名 flatMap ),您可以使用以前的Observable发出的结果,如下所示:

SUM

答案 8 :(得分:0)

嗯,我知道这已经很老了,但我认为您可能需要的是:

var one = someObservable.take(1);

var two = someOtherObservable.pipe(
  concatMap((twoRes) => one.pipe(mapTo(twoRes))),
  take(1)
).subscribe((twoRes) => {
   // one is completed and we get two's subscription.
})