6

I have several cases on my software where I have an array of observables and I need to execute them in order. Having the next subscription to happen only after the previous is complete.

So Im using the concat operator. It works great, however its subscription gets triggered every time one of the Observables gets completed, and I need to have it be triggered only after everything is complete.

concat(
  of(1, 2, 3).pipe(delay(3000)),
  // after 3s, the first observable will complete and subsquent observable subscribed with values emitted
  of(4, 5, 6).pipe(delay(3000)),
)
  // log: 1,2,3,4,5,6
  .subscribe((v) => {
  // Needs to be triggered once after everything is complete
    console.log(v);
  });

I need a way to pipe this observable so the subscription gets triggered only once after everything is complete, the value of the subscription is not important in this case, so it can be omitted.

If possible the values could be made available in a form of an array inside the subscription context.

João Eduardo
  • 738
  • 7
  • 21
  • This might help: https://stackoverflow.com/questions/41734921/rxjs-wait-for-all-observables-in-an-array-to-complete-or-error. – Rajesh May 15 '19 at 13:10

2 Answers2

12

Collect the values in an array with toArray.

import { toArray } from 'rxjs/operators';

concat(
  of(1, 2, 3).pipe(delay(3000)),
  of(4, 5, 6).pipe(delay(3000)),
).pipe(
  toArray()
).subscribe(v => console.log(v)); // log: [1,2,3,4,5,6]

Or if you don't need the response use the complete callback like in @Willem's solution.

frido
  • 13,065
  • 5
  • 42
  • 56
  • 1
    This works best because its a cleaner solution on my context, adding the `complete callback` everywhere the observable is being used would be hard. And as an added bonus If I ever need the data it will be made available as an Array. – João Eduardo May 15 '19 at 13:30
3

Pipe the results into a finalize():

Call a function when observable completes or errors

See https://www.learnrxjs.io/operators/utility/finalize.html

Subscribe to the complete event:

.subscribe({
  complete: () => { ... }
})

Use forkJoin(), especially if you want the final values:

When all observables complete, emit the last emitted value from each.

https://www.learnrxjs.io/operators/combination/forkjoin.html

w5l
  • 5,341
  • 1
  • 25
  • 43
  • 4
    I don't think `forkJoin` is what the OP wants at it won't execute the observables in order. – frido May 15 '19 at 13:21
  • forkJoin cannot be used in this context since it won't wait for the previous observable in order to subscribe to the next @fridoo 's solution works best for me, the `toArray()` pipe its a much cleaner solution for my context. – João Eduardo May 15 '19 at 13:25