I want to somehow chain two web requests such that:
Observable<void>
) is always run.Observable<void>
) is also always run, after A and even when A completes with errors (like finalize()
).This is the solution I could come up with, but it feels very clumsy:
// Changes different parts of backend state in multiple steps,
// some of which might fail.
const reqA: Observable<void> = this.mutateSystemState();
// Loads & renders the system state, updating the parts that
// could be changed.
const reqB: Observable<void> = this.updateSystemStateDisplay();
const pipeline = reqA.pipe(
catchError(e => of({ errA: e })),
mergeMap(resultA => reqB.pipe(
catchError(e => of({ errB: e })),
map(resultB => {
if (resultA instanceof Object) {
throw resultA.errA;
} else if (resultB instanceof Object) {
throw resultB.errB;
}
})
))
);
The materialize operator converts next, error, or completion 'events' into ObservableNotification objects.
Assuming you want pipeline$
to either error or complete without emitting a value, you can do the following:
const pipeline$ = reqA.pipe(
materialize(),
concatMap(a => reqB.pipe(
materialize(),
map(
// Both have executed.
// Both a & b are ObservableNotification objects
// Emit a if ErrorNotification
b => a.kind === 'E' ? a
// Otherwise emit CompleteNotification if b is a NextNotification
: b.kind === 'N' ? {kind: 'C'}
// Otherwise emit b
: b
)
)),
// At this point, we've got reqA's ErrorNotification, reqB's ErrorNotification or a CompleteNotification.
// Either way, this observable is closing before the first materialize gets a chance to emit reqA's CompleteNotification
dematerialize()
);
onErrorResumeNext()
whatever reqA$
error or not, will subscribe reqB$
reqA$.pipe(
onErrorResumeNext(reqB$)
).subscribe(...);
https://stackblitz.com/edit/rxjs-ps5f1j
const pipeline$ = of(reqA$, reqB$).pipe(
concatMap(materialize()),
filter(({kind}) => kind === 'E'), // filter Error
reduce(identity), // collect then return first value
dematerialize(),
);
or
const pipeline$ = of(reqA$, reqB$).pipe(
concatMap(materialize()),
max(({kind}) => +(kind === 'E')),
dematerialize(),
);
https://stackblitz.com/edit/rxjs-jnqhjw
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With