How to use withLatestFrom with a promise?

Viewed 593

Why isn't it possible to convert a promise to an observable and then use it with withLatestFrom. It's not clear to me, why this doesn't resolve.

of('')
  .pipe(
    withLatestFrom(from(myPromise)),
    map((res) => {
      console.log('does not resolve', res);
    })
  )
  .subscribe();
2 Answers

WithLatestFrom emits only when its source Observable emits, since of('') emits before the source to withLatestFrom, your withLatestFrom is never triggered.

The following code will not work:

of('1 + 1')
  .pipe(
    withLatestFrom(new Promise(x => x("== 2"))),
    map(([res1,res2]) => console.log(res1, res2))
  )
  .subscribe();

but this will:

of('1 + 1')
  .pipe(
    delay(100), // <= delay source execution
    withLatestFrom(new Promise(x => x("== 2"))),
    map(([res1,res2]) => console.log(res1, res2))
  )
  .subscribe();

This is expected behaviour for withLatestFrom. The source observable completes synchronously before the promise resolves (asynchronously). withLatestFrom only emits once both observables have emitted at least once and then only emits when the source observable emits.

In your case, the source observable is complete before the promise resolves.

of('').pipe(
  delay(100),
  withLatestFrom(from(myPromise)),
  tap(res =>
    console.log('should resolve', res)
  )
).subscribe();

Update #1 : solutions without delay

If both source observables emit once and complete, then forkJoin is best

forkJoin({
  addition: of(1 + 1),
  promise: from(myPromise)
}).pipe(
  map(({addition, promise}) => {return /* something */})
)

combineLatest is similar to forkJoin but it works better with long-lived streams that keep emitting values. It waits for its inner streams to all start emitting and then emits all their latest values.

combineLatest(
  of(1 + 1),
  from(myPromise)
).pipe(
  map(([addition, promise]) => {return /* something */})
)

Or, if you want to use withLatestFrom and your comfortable with the timing constraints.

from(myPromise).pipe(
  withLatestFrom(of(1+1)),
  map(([promise, addition]) => {return /* something */})
)

should work.

Related