Итак, я начал играть с rxjs, и у меня возник вопрос о том, как лучше сохранить свою наблюдаемую жизнь после получения ошибки от вызова веб-службы.
Перед показом кода вот мой текущий сценарий: угловой компонент, который должен загрузить начальный список, который разбит на страницы и который также может быть отфильтрован путем изменения элемента в комбо. Чтобы решить эту проблему с помощью rxjs, я подумал о слиянии двух наблюдаемых: одна обрабатывает событие изменения выбора, а другая используется для загрузки большего количества элементов. Вот код, который я использую:
const filtro$ = this.estadoPedido.valueChanges.pipe(
distinctUntilChanged(),
tap(_ => {
this._paginaAtual = 0;
this.existemMais = true;
}),
startWith(this.estadoPedido.value),
map(estado => new DadosPesquisa(this._paginaAtual,
this._elemsPagina,
estado,
false))
);
Всякий раз, когда выбор изменяется, я в итоге сбрасываю глобальный счетчик страниц (оператор tap
), и, поскольку я хочу получить начальную загрузку, я также использую оператор startWith
. Наконец, я преобразую текущее состояние в объект, который имеет все необходимые значения для загрузки значений.
У меня также есть Тема, которая используется всякий раз, когда нажимается кнопка загрузки дополнительных элементов:
dataRefresh$ = new Subject<DadosPesquisa>();
И эти две наблюдаемые объединены, чтобы у меня был единственный путь для вызова моего веб-сервиса:
this.pedidosCarregados$ = merge(filtro$, this.dataRefresh$).pipe(
tap(() => this.emChamadaRemota = true),
switchMap(info => forkJoin(
of(info),
this._servicoPedidos.obtemPedidos(this._idInstancia,
info.paginaAtual,
info.elemsPagina,
info.estado)
)),
shareReplay(),
tap(([info, pedidos]) => this.existemMais = pedidos.length === info.elemsPagina),
scan((todosPedidos, info) => !info[0].addPedidosToExisting ?
info[1] :
todosPedidos.concat(info[1]), []),
tap(() => this.emChamadaRemota = false),
catchError(erro => {
this.emChamadaRemota = false;
this.trataErro(erro);
this.existemMais = false;
return of([]);
})
);
Просто краткий обзор того, что я пытаюсь сделать здесь ... tap
используется для установки и очистки поля, которое управляет счетчиком ожидания (emChamadaRemota
), и для контроля, должна ли быть кнопка загрузки еще показано (existemMais
). Я использую forkJoin
внутри switchMap
, потому что мне нужно получить доступ к информации о текущем поиске по конвейеру. scan
есть, потому что загрузка большего количества элементов должна добавить элементы на предыдущую загруженную страницу.
Теперь я также использую перехватчик, который отвечает за установку правильных заголовков и обработку типичных ошибок (401, 503 и т. Д.) С помощью стратегии повторных попыток. Вот код для intercept
метода:
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const headers = this.obtemHeaders();
const requestClonado = req.clone({ headers });
return next.handle(requestClonado).pipe(
retryWhen(this.retryStrategy()),
catchError(err => {
console.error(err);
let msgErro: string;
if(err instanceof HttpErrorResponse && this._servicoAutenticacao.trataErroFimSessao(err)) {
msgErro = "A sua sessão terminou. Vai ser redirecionado para a página de login" ;
}
else if(err.status === 503 ) {
msgErro = "O servidor não devolveu uma resposta válida (503).";
}
else {
msgErro = err.error && err.error.message ? err.error.message : "Ocorreu um erro no servidor.";
}
if(err.status !== 503) {
this._logger.adicionaInfoExcecao(msgErro).subscribe();
}
return throwError(msgErro);
}
));
}
Теперь проблема: если я получаю ошибку при вызове веб-службы, все работает хорошо, но моя наблюдаемая будет «убита» ... и это имеет смысл, потому что операторы должны отловить ошибку и «отписаться» поток (по крайней мере, это то, что я понял из некоторых статей, которые я прочитал).
Я читал некоторые статьи, в которых говорится, что решение состоит в создании внутренней наблюдаемой, которая никогда не генерирует и которая оборачивает наблюдаемую информацию, возвращаемую вызовом веб-службы. Это путь? Если так, могу ли я сделать это на уровне перехватчика? Или, в случае ошибки, я должен просто перестроить свою наблюдаемую цепочку (но без автоматического запуска ее с помощью оператора startWith)?