最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - RxJS: map promise result and promise error to different values - Stack Overflow

programmeradmin2浏览0评论

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);
});
发布评论

评论列表(0)

  1. 暂无评论