Quero lançar um erro do operador de mapa do meu observável com base em uma condição. Por exemplo, se os dados API corretos não forem recebidos. Por favor, veja o seguinte código:
private userAuthenticate( email: string, password: string ) {
return this.httpPost(`${this.baseApiUrl}/auth?format=json&provider=login`, {userName: email, password: password})
.map( res => {
if ( res.bearerToken ) {
return this.saveJwt(res.bearerToken);
} else {
// THIS DOESN'T THROW ERROR --------------------
return Observable.throw('Valid token not returned');
}
})
.catch( err => Observable.throw(this.logError(err) )
.finally( () => console.log("Authentication done.") );
}
Basicamente, como você pode ver no código, se a resposta (objeto res) não tiver 'bearerToken', quero exibir um erro. Para que na minha assinatura vá para o segundo parâmetro (handleError) mencionado abaixo.
.subscribe(success, handleError)
Alguma sugestão?
angular
typescript
rxjs
Hassan
fonte
fonte
throw 'Valid token not returned';
?return throw 'message here'
areturn
palavra - chave, mas funciona sem . Deixe-me verificar se está funcionando corretamente logicamente.subscribe
método e.finally()
no fluxo também é acionado. (No entanto, a execução é interrompida, o que é uma coisa boa)Respostas:
Basta jogar o erro dentro do
map()
operador. Todos os retornos de chamada em RxJS são agrupados com blocos try-catch para que sejam capturados e enviados como umaerror
notificação.Isso significa que você não retorna nada e apenas lança o erro:
map(res => { if (res.bearerToken) { return this.saveJwt(res.bearerToken); } else { throw new Error('Valid token not returned'); } })
o
throwError()
(antigoObservable.throw()
em RxJS 5) é um Observable que apenas envia umaerror
notificação, masmap()
não se importa com o que você retorna. Mesmo se você retornar um Observávelmap()
dele, será passado como umanext
notificação.Por último, você provavelmente não precisa usar
.catchError()
(antigocatch()
em RxJS 5). Se você precisar realizar algum efeito colateral quando ocorrer um erro, é melhor usartap(null, err => console.log(err))
(antigodo()
em RxJS 5), por exemplo.Janeiro de 2019: Atualizado para RxJS 6
fonte
return
o objeto de erro dele e agora funciona perfeitamente :) Obrigado!catch()
apenas para registrar e relançar o erro, o que é desnecessário se você quiser apenas executar um efeito colateral (registrar o erro) e é mais fácil de usar apenasdo()
return throwError(new Error('Valid token not returned'));
?return throwError()
retorna umObservable<never>
, isso apenas interrompe o fluxo observável imediatamente, sem retornar de forma alguma.Se você sentir que
throw new Error()
parece não observável, você pode usarthrowError(...)
com emswitchMap
vez demap
(a diferença sendoswitchMap
retorna um novo observável):// this is the import needed for throwError() import { throwError } from 'rxjs'; // RxJS 6+ syntax this.httpPost.pipe(switchMap(res => { if (res.bearerToken) { return of(this.saveJwt(res.bearerToken)); } else { return throwError('Valid token not returned'); // this is } });
ou mais concisamente:
this.httpPost.pipe(switchMap(res => (res.bearerToken) ? of(this.saveJwt(res.bearerToken)) : throwError('Valid token not returned') ));
O comportamento será o mesmo, é apenas uma sintaxe diferente.
Você está literalmente dizendo 'mudar' do http observável no tubo para um observável diferente, que está apenas 'envolvendo' o valor de saída ou um novo 'erro' observável.
Não se esqueça de colocar
of
ou você receberá algumas mensagens de erro confusas.Além disso, a beleza de 'switchMap' é que você pode retornar uma nova 'cadeia' de comandos se quiser - para qualquer lógica que precise ser feita
saveJwt
.fonte
switchMap
em umaif
instrução assíncrona - as coisas fizeram muito mais sentido :-)Mesmo que essa pergunta já tenha sido respondida, eu gostaria de compartilhar minha própria abordagem (embora seja apenas ligeiramente diferente da anterior).
Eu decidiria o que é retornado separado do mapeamento e vice-versa. Não tenho certeza de qual operadora é melhor para isso, então vou usar
tap
.this.httpPost.pipe( tap(res => { if (!res.bearerToken) { throw new Error('Valid token not returned'); } }), map(res => this.saveJwt(res.bearerToken)), );
fonte
tap
é ignorado. este código faz uma coisa diferente do que dizthrow new Error()
é a melhor opção até agora