Обработка исключения в вызове rxjs ajax.map

Я создал эпопею на основе "выборки пользователей" на сайте, доступном для наблюдения за Redux.

Мне просто интересно, как я могу добавить обработку ошибок в запрос ajax. Моя попытка:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response),
          error => console.log(error)
        )
    )

Я тестирую, пока API, который я вызываю, не работает для проверки обработки ошибок. Все еще получаю это в консоли, и приложение вылетает:

ExceptionsManager.js: 71 Необработанное исключение JS: ошибка ajax 0

Если это официальная документация тогда мне избавиться от карты и вместо этого подписаться?

Я изменил это на это:

import 'rxjs/add/operator/catch'

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        ).catch( err => console.log(err))
    )

Но получил:

Вы предоставили undefined там, где ожидался поток. Вы можете предоставить наблюдаемый, обещанный, массив или итерируемый

изменено на (согласно ответу Джея Фелпса здесь):

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(response => fetchCategoriesFulfilled(response))
        .catch( err => Observable.of(err.xhr.response))
    )

есть:

Действия должны быть простыми объектами. Используйте собственное промежуточное ПО для асинхронных действий

Что я делаю не так?


person BeniaminoBaggins    schedule 21.04.2017    source источник


Ответы (1)


https://github.com/Reactive-Extensions/RxJS-DOM для RxJS v4, а не v5. Документы для v5 находятся здесь: http://reactivex.io/rxjs/, а исходный код здесь https://github.com/ReactiveX/rxjs.

Это определенно сбивает с толку, но это печальная реальность по сложным причинам.


Вы предоставили undefined там, где ожидался поток. Вы можете предоставить наблюдаемый, обещанный, массив или итерируемый

Причина, по которой вы получаете эту ошибку, действительно заключается в том, что вы не возвращаете поток из своего использования оператора catch, как это необходимо.

В документах с возможностью наблюдения за редуксом есть рецепт обработки ошибок здесь: https://redux-observable.js.org/docs/recipes/ErrorHandling.html

Так что это будет выглядеть примерно так:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .catch(error => Observable.of({
          type: FETCH_CATEGORIES_REJECTED,
          error
        }))
    )

Если вы на самом деле не хотите отлавливать ошибки и возвращать другой Observable (например, Observable одного действия с ошибкой), вы можете использовать .do(), чтобы просто зарегистрировать ошибку:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .do({
          error: err => console.log(err)
        })
    )

Однако, если вы не поймаете ошибку, она будет распространяться вверх по цепочке источников, завершая этот эпик, а затем продолжая распространяться, завершая корневой эпик, что делает ваше приложение, вероятно, непригодным для использования.

Хотя я не рекомендую этого делать, если вы действительно хотите поймать ошибку, но просто проглотить ее без диспетчеризации и действий с ошибкой, вы можете сделать это:

const fetchCategoriesEpic = action$ =>
  action$.ofType(FETCH_CATEGORIES)
    .mergeMap(() =>
      ajax.getJSON(`http://localhost:4000/categories`)
        .map(
          response => fetchCategoriesFulfilled(response)
        )
        .catch(error => {
          console.error(error);
          return Observable.empty();
        })
    )

Опять же, я бы крайне не одобрял это — если есть ошибка, о которой вы достаточно заботитесь, чтобы ее отловить, вам, вероятно, следует каким-то образом обработать ее, например, отобразить ошибку пользователю, отправив действие ошибки и обработав его.


Изменить: на основе ваших новых дополнений

.catch( err => Observable.of(err.xhr.response))

Действия должны быть простыми объектами. Используйте собственное промежуточное ПО для асинхронных действий

Действительно, ваш эпик теперь выдает ответ XHR при ошибке, а не избыточное действие. Ваш эпик может испускать только действия.

person jayphelps    schedule 21.04.2017
comment
Я могу быть слепым, но все, что я вижу на reactivex.io/rxjs, это: observable/dom CAjaxError CAjaxResponse CAjaxTimeoutError IAjaxRequest. Где документы, описывающие, как на самом деле его использовать? - person badbishop; 01.11.2017