Как отправить запрос последовательно с проверками перед каждым запросом? - PullRequest
0 голосов
/ 16 ноября 2018

Мне нужно:

  • отправка N запросов последовательно (для этого я использую concatMap)
  • только если объект действителен (я расширяю карту concat с кодом проверки)
  • остановка очереди при первой ошибке (ответом на ошибку сервера или отклонением проверки клиента)

Теперь код выглядит так:

ids = [{valid: true, id: 1}, {valid: true, id: 2}, {valid: true, id: 3}, {valid: false, id: 4}]
constructor(httpClient: HttpClient) {
  from(this.ids)
  .pipe(
    map(obj => ({...obj, id: obj.id + 5})),
    concatMap(obj => {
      console.log('concat map');
      if (obj.valid === false) {
        return throwError('not valid');
      } else {
        return httpClient.get(`https://jsonplaceholder.typicode.com/todos/${obj.id}`);
      }
    })
  )
  .subscribe(
    result => console.log('success', result),
    result => console.log('error', result),
    () => console.log('complete')
  );
}

Вот стекаблитц: https://stackblitz.com/edit/angular-5vwbjg

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

  1. map + concatMap по первому идентификатору
  2. map + concatMap для второго идентификатора
  3. и еще больше больше ...

Я справился с этим только путем расширения кода concatMap. Возможно ли каким-то образом извлечь эту проверку другому оператору, работающему с конвейером, до concatMap? Так что concatMap тело будет проще.

Я попробовал оператор слияния, как:

mergeMap(obj => {
  console.log(obj);
  if (obj.valid === false) {
    return throwError('not valid');
  } else {
    return of(obj);
  }
}),

И я получил это в консоли:

enter image description here

Это неверный результат. Я ожидаю 3 запроса, а затем 1 ошибка. Ожидаемый результат:

enter image description here

Также, возможно, есть более красивый способ описать функцию проверки в моем случае? Есть идеи? Без этого if с 2 ветками.

Я думаю, что неправильно понял этот момент. from(this.ids) все равно выдает значения. Не ждет concatMap или карта или любой другой оператор. В тот момент, когда новое значение передается в from(this.ids) (это будет до окончания concatMap), оно обрабатывает всю цепочку: map + concatMap. Что-то, что мне нужно, это как-то сказать, что rxjs обрабатывает 2-е излучаемое значение после того, как concatMap завершил обработку 1-го. Затем он должен обработать 3-е испущенное значение, после того как concatMap завершит обработку 2-го e c c.

Немного расширенный пример здесь: https://stackblitz.com/edit/angular-ovffm4?file=src/app/app.component.ts

Здесь у меня есть 2 проверки клиента и 1 ответ сервера.

Вот что я вижу в консоли:

map
first check true
second check 6
make request
map
first check true
second check 7
map
first check true
second check 8
map
first check true
second check 9
map
first check true
second check 10
map
first check false
success {userId: 1, id: 6, title: "qui ullam ratione quibusdam voluptatem quia omnis", completed: false}
make request
success {userId: 1, id: 7, title: "illo expedita consequatur quia in", completed: false}
complete

Как изменить мою наблюдаемую так, чтобы она выглядела так:

map
first check true
second check 6
make request
success {userId: 1, id: 6, title: "qui ullam ratione quibusdam voluptatem quia omnis", completed: false}
map
first check true
second check 7
make request
success {userId: 1, id: 7, title: "illo expedita consequatur quia in", completed: false}
map
first check true
second check 8
map
first check true
second check 9
map
first check true
second check 10
map
first check false
complete

1 Ответ

0 голосов
/ 16 ноября 2018

Для начала, я думаю, вы неправильно поняли, как работает обработка ошибок в rxjs. Функция обработки ошибок, которую вы передаете в качестве второго параметра функции подписки, никогда не будет вызываться более одного раза. Как только наблюдаемая обнаруживает одну-единственную ошибку, она завершена и больше не функционирует. Таким образом, вы не можете использовать эту функцию для перехвата нескольких ошибок.

http://reactivex.io/documentation/operators/subscribe.html

Observable вызывает этот метод, чтобы указать, что ему не удалось сгенерировать ожидаемые данные или произошла какая-то другая ошибка. Это останавливает Observable и не будет делать дальнейшие вызовы onNext или onCompleted. Метод onError принимает в качестве параметра указание того, что вызвало ошибку (иногда такой объект, как Exception или Throwable, иногда простой строка, в зависимости от реализации).

Вы никогда не сможете с этим справиться.

Это может быть альтернативный способ:

https://stackblitz.com/edit/angular-wbu3tv

Отрывок:

  concatMap(obj => {
    console.log(obj);
    if (obj.valid === false) {
      return of({
          response: null,
          success: false
        });
    } else {
      return httpClient.get(`https://jsonplaceholder.typicode.com/todos/${obj.id}`).pipe(map(response => {
        return {
          response: response,
          success: true
        }
      }));
    }
  })

Таким образом, в основном, вместо использования throwError, я возвращаю объект, который указывает, был ли выполнен запрос, и ответ, если он был выполнен.

...