admin管理员组

文章数量:1328557

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?

Share asked Nov 19, 2017 at 19:32 Chris CaloChris Calo 7,8388 gold badges52 silver badges67 bronze badges 1
  • 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
Add a ment  | 

4 Answers 4

Reset to default 3

Wrap 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);
});

本文标签: javascriptRxJS map promise result and promise error to different valuesStack Overflow