Как отправить запрос последовательно с проверками перед каждым запросом?
Я нуждаюсь:
- отправлять 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 из начального наблюдаемого, только если обработка предыдущего закончена. Поэтому я хочу течь, как:
- map + concatMap по первому идентификатору
- map + concatMap для второго идентификатора
- и еще больше больше...
Я справился с этим только путем расширения кода concatMap. Можно ли каким-то образом извлечь эту проверку другому оператору канала перед тем, как concatMap
? Так concatMap
тело будет проще.
Я попробовал оператор слияния, как:
mergeMap(obj => {
console.log(obj);
if (obj.valid === false) {
return throwError('not valid');
} else {
return of(obj);
}
}),
И я получил это в консоли:
Это не правильный результат. Я ожидаю 3 запроса, а затем 1 ошибка. Ожидаемый результат:
Также, может быть, есть более красивый способ описать функцию проверки в моем случае? Есть идеи? Без этого if
с 2 ветками.
Я думаю, что я неправильно понял этот момент. from(this.ids)
все равно испускает значения. Не ждет concatMap
или карта или любой другой оператор. В тот момент, когда новое значение выделяется в from(this.ids)
(это будет раньше concatMap
заканчивается) это обрабатывает всю цепочку: map
+ concatMap
, Что мне нужно, так это как-то сказать, что rxjs обрабатывает 2-е излученное значение после concatMap
закончил обработку 1-го. Затем он должен обработать 3-е излучаемое значение, после concatMap
закончил обработку 2-й и т. д.
Немного расширенный пример здесь: 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 ответ
Для начала, я думаю, вы не поняли, как работает обработка ошибок в rxjs. Функция обработки ошибок, которую вы передаете как второй параметр функции подписки, никогда не будет вызываться более одного раза. Как только наблюдаемая встречает одну ошибку, она завершается и перестает функционировать. Таким образом, вы не можете использовать эту функцию, чтобы поймать несколько ошибок.
http://reactivex.io/documentation/operators/subscribe.html
Observable вызывает этот метод, чтобы указать, что ему не удалось сгенерировать ожидаемые данные или произошла какая-то другая ошибка. Это останавливает Observable и не будет делать дальнейшие вызовы onNext или onCompleted. Метод onError принимает в качестве параметра указание того, что вызвало ошибку (иногда такой объект, как исключение или Throwable, иногда простая строка, в зависимости от реализации).
Вы никогда не сможете справиться с этим таким образом.
Это может быть альтернативный способ:
https://stackblitz.com/edit/angular-wbu3tv
Snippet:
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, я возвращаю объект, который указывает, был ли выполнен запрос, и ответ, если он был выполнен.