The following code effectively maps promise resolution to true
and a promise error to false
.
onlineUpdate$
.switchMap(online => {
switch (online) {
default:
case true: {
const connected$ = new Rx.Subject();
axios.get("/some/url/to/test/connection")
.then(response => connected$.next(true))
.catch(error => connected$.next(false));
return connected$;
}
case false: {
return Rx.Observable.of(false);
}
}
});
But something about creating the intermediate Rx.Subject
feels like I'm doing more work than I need to. Is there a more elegant or built-in way to map promise resolution to one value and promise error to another without the use of an intermediate Rx.Subject
or other observable?
The following code effectively maps promise resolution to true
and a promise error to false
.
onlineUpdate$
.switchMap(online => {
switch (online) {
default:
case true: {
const connected$ = new Rx.Subject();
axios.get("/some/url/to/test/connection")
.then(response => connected$.next(true))
.catch(error => connected$.next(false));
return connected$;
}
case false: {
return Rx.Observable.of(false);
}
}
});
But something about creating the intermediate Rx.Subject
feels like I'm doing more work than I need to. Is there a more elegant or built-in way to map promise resolution to one value and promise error to another without the use of an intermediate Rx.Subject
or other observable?
-
While in this particular case not much can happen, I still would remend
.then(…, …)
over.then(…).catch(…)
– Bergi Commented Nov 20, 2017 at 5:38
4 Answers
Reset to default 3Wrap the Promise into an Observable via Observable#fromPromise function and pass the the promise into. Observable will emit true
if the Promise is resolved or false
if it is rejected
...
case true: {
return Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection")
.then(response => true)
.catch(error => false));
}
...
Simple Example.
Rx.Observable.of(false
) is equivalent to the case false
.
Promise.resolve(true)
to the then
function of the promise and Promise.reject('Error').catch(err => false)
to the catch
function of the promise.
Rx.Observable.of(false).subscribe(console.log);
Rx.Observable.fromPromise(Promise.resolve(true)).subscribe(console.log);
Rx.Observable.fromPromise(Promise.reject('Error').catch(err => false)).subscribe(console.log);
<script src="https://unpkg./@reactivex/[email protected]/dist/global/Rx.js"></script>
Yes, you can just return Observable.of(false)
in the catch block of the Observable.fromPromise()
. Like wise, use .map()
to return Observable.of(true)
if the connection is successful.
onlineUpdate$
.switchMap(online => {
switch (online) {
default:
case true: {
Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection"))
.map(() => true) // if the promise resolves to something, return an Observable.of(true)
.catch(() => Rx.Observable.of(false)) // else if there is any error return Observable.of(false)
}
case false: {
return Rx.Observable.of(false);
}
}
});
Note that you have to explicitly .map()
the Observable.fromPromise
to true if the promise
resolves successfully.
You can write the code in a much more succinct way:
onlineUpdate$
.switchMap(online => {
return online ?
Rx.Observable.fromPromise(axios.get("/some/url/to/test/connection"))
.map(() => true)
.catch(() => Observable.of(false))
: Observabe.of(false)
});
The switchMap
operator works with so-called Observable input which means you can just return the Promise without turning it into an Observable:
onlineUpdate$
.switchMap(online => {
switch (online) {
default:
case true: {
return axios.get("/some/url/to/test/connection");
}
case false: {
return Rx.Observable.of(false);
}
}
})
.catch(() => Rx.Observable.of(false))
.map(Boolean) // force convert to boolean
Just be aware this isn't the same as what you wrote. The catch
operator will catch all errors even if they don't e from the preceding axios.get
call but maybe it doesn't matter in your case.
It turns out there's no need to use Observable.fromPromise()
at all. The most straightforward change to make this work is:
onlineUpdate$
.switchMap(online => {
switch (online) {
default:
case true: {
return axios.get("/some/url/to/test/connection")
.then(response => true)
.catch(error => false);
}
case false: {
return Rx.Observable.of(false);
}
}
});
Or, if you prefer ternaries over switch
statements:
onlineUpdate$
.switchMap(online => {
return online ?
axios.get("/some/url/to/test/connection")
.then(response => true)
.catch(error => false)
: Rx.Observable.of(false);
});