Quiero lanzar un error del operador de mapa de mi observable basado en una condición. Por ejemplo, si no se reciben los datos de API correctos. Consulte el siguiente 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.") );
}
Básicamente, como puede ver en el código, si la respuesta (objeto res) no tiene 'bearerToken', quiero arrojar un error. De modo que en mi suscripción entra en el segundo parámetro (handleError) mencionado a continuación.
.subscribe(success, handleError)
¿Alguna sugerencia?
angular
typescript
rxjs
Hassan
fuente
fuente
throw 'Valid token not returned';
?return throw 'message here'
lareturn
palabra clave, pero funciona sin ella . Déjame comprobar si funciona correctamente de forma lógica.subscribe
método y.finally()
también se activa en la secuencia. (Sin embargo, la ejecución se detiene, lo cual es bueno)Respuestas:
Simplemente arroje el error dentro del
map()
operador. Todas las devoluciones de llamada en RxJS están envueltas con bloques try-catch para que se detecten y luego se envíen como unaerror
notificación.Esto significa que no devuelve nada y simplemente arroja el error:
map(res => { if (res.bearerToken) { return this.saveJwt(res.bearerToken); } else { throw new Error('Valid token not returned'); } })
El
throwError()
(primeroObservable.throw()
en RxJS 5) es un Observable que solo envía unaerror
notificación peromap()
no le importa lo que devuelva. Incluso si devuelve un Observablemap()
, se pasará comonext
notificación.Por último, probablemente no necesite usar
.catchError()
(anteriormentecatch()
en RxJS 5). Si necesita realizar algún efecto secundario cuando ocurre un error, es mejor usartap(null, err => console.log(err))
(antesdo()
en RxJS 5) por ejemplo.Enero de 2019: actualizado para RxJS 6
fuente
return
el objeto de error y ahora funciona perfectamente :) ¡Gracias!catch()
solo para registrar y volver a lanzar el error, lo cual es innecesario si solo desea realizar un efecto secundario (registrar el error) y es más fácil de usardo()
return throwError(new Error('Valid token not returned'));
?return throwError()
devuelve unObservable<never>
, esto simplemente interrumpe la secuencia observable inmediatamente, sin regresar en absoluto.Si siente que
throw new Error()
parece no observable, puede usarthrowError(...)
con enswitchMap
lugar demap
(la diferenciaswitchMap
devuelve un nuevo observable):// 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 } });
o más concisamente:
this.httpPost.pipe(switchMap(res => (res.bearerToken) ? of(this.saveJwt(res.bearerToken)) : throwError('Valid token not returned') ));
El comportamiento será el mismo, solo es una sintaxis diferente.
Literalmente está diciendo 'cambiar' del observable http en la tubería a un observable diferente, que es simplemente 'envolviendo' el valor de salida, o un nuevo 'error' observable.
No olvide poner
of
o obtendrá algunos mensajes de error confusos.Además, la belleza de 'switchMap' es que puede devolver una 'cadena' completamente nueva de comandos si lo desea, para cualquier lógica que necesite
saveJwt
.fuente
switchMap
en unaif
declaración asincrónica , las cosasAunque esta pregunta ya está respondida, me gustaría compartir mi propio enfoque (aunque es solo un poco diferente al anterior).
Yo decidiría qué se devuelve por separado del mapeo y viceversa. No estoy seguro de qué operador es mejor para esto, así que lo usaré
tap
.this.httpPost.pipe( tap(res => { if (!res.bearerToken) { throw new Error('Valid token not returned'); } }), map(res => this.saveJwt(res.bearerToken)), );
fuente
tap
se ignora. este código hace algo diferente de lo que dicethrow new Error()
es la mejor opción hasta ahora