Picci
Picci

Reputation: 17762

RxJs race function - make sure that the first to occur wins

I have 2 different Observables, let's call them racer_1 and racer2, which emit when 2 different events occur.

If racer_1 occurs I have to perform the logic of function doStuff_1(), if racer_2 occurs I have to perform doStuff_2().

racer_1 and racer_2 are not mutually exclusive and they can occur one after the other, but what I want to achieve is that if any of them occur, I process just that one with its associated function.

It seems clearly the case of using the race function of RxJs.

race(
    racer_1.pipe(
        tap(() => doStuff_1()),
        finalize(() => console.log('racer 1 completed'))
    ),
    racer_2.pipe(
        tap(() => doStuff_2()),
        finalize(() => console.log('racer 2 completed'))
    )
)

Unfortunately though it may happen that racer_1 emits first at t0 and doStuff_1() starts a synchronous execution which ends at t0+1000.

In the meantime, at t0+200 racer_2 emits and the execution of doStuff_2() is much shorter so that it ends at t0+300.

In this case what I see is that racer_2 "wins the race" and its emissions continue to get processed, while racer_1 gets completed.

On the contrary what I would like to see is that racer_1 wins since it occurred first, even if its processing can get long to be completed.

Is there a way to obtain such behavior?

Upvotes: 1

Views: 490

Answers (1)

martin
martin

Reputation: 96889

You can just reorder operators and wrap the initial emissions from both source Observables and perform doStuff_1 or doStuff_2 later:

race( // wrap emissions with tmp objects
    racer_1.pipe(map(result => { type: 'racer1', result })),
    racer_2.pipe(map(result => { type: 'racer2', result })),
  )
  .tap(({ type, result }) => type === 'racer1'
    ? doStuff_1() 
    : doStuff_2()
  )
  map(({ type, result }) => result) // unwrap the object

Upvotes: 1

Related Questions