简体   繁体   中英

Combining multiple observables and acting when at least one value is returned in Angular

I have a set of observables and I'll need to react when the last one has provided a value (whichever that one will be).

My first approach was forkJoin like this.

const observables = [
  this.backend.config(),
  this.navigation.location()
];

forkJoin(observables)
  .subscribe(([backend, selection]) => {
    console.log(backend);
    console.log(selection);
  });

This worked partly as long as the observables emit complete at some point (upon which, the finalization is invoked. Then I tried combineLatest . That resolved the original issue but created a new one. Now, I get the final method invoked as soon as any of the observables provides.

I'd like to get it invoked when each of the observables has provided at least once and might or might not have completed. It doesn't mater if it's the latest value from each or if it's the first one. Although, it might be a plus to learn how to control that as well for +1.

The best, yet hacky, solution I came up with is to check !!backend and !!navigation and only act if all of them satisfy. I'm looking for a smoother solution or confirmation that the one I'm using is as good as it gets.

combineLatest(observables)
  .subscribe(([a, b, c]) => {
    if (!a || !b || !c)
      console.log("Oh, I'm coming...");
    else
      console.log("Wham, bam - I'm done!");
  });

All that from blogs like this or that , posts on SO and Observables' docs .

Well you describe the right operator:

combineLatest will not emit an initial value until each observable emits at least one value

So I believe your issue is different, maybe some of your sources emit a null/undefined value?

ref https://www.learnrxjs.io/operators/combination/combinelatest.html

Use zip instead of forkJoin . It works similar but doesn't require observables to complete.

const a$ = of('a');                       // will complete instantly
const b$ = timer(2000).pipe(mapTo('b'));  // will complete later 
const c$ = new BehaviorSubject('c');      // will never complete

zip(a$, b$, c$).subscribe(console.log)    // (after 2s) ['a', 'b', 'c']

demo: https://stackblitz.com/edit/rxjs-ycqqhn

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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