Angular 2 usando RxJS – toma (1) frente a la primera ()

Encontré poca implementación de Auth Guards que usa take(1) . En mi proyecto, utilicé first() para satisfacer mis necesidades. ¿Funciona de la misma manera? O uno de ellos podría tener ventajas más o menos.

 import 'rxjs/add/operator/map'; import 'rxjs/add/operator/first'; import { Observable } from 'rxjs/Observable'; import { Injectable } from '@angular/core'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { AngularFire } from 'angularfire2'; @Injectable() export class AuthGuard implements CanActivate { constructor(private angularFire: AngularFire, private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean { return this.angularFire.auth.map( (auth) => { if (auth) { this.router.navigate(['/dashboard']); return false; } else { return true; } } ).first(); // Just change this to .take(1) } } 

Los operadores first() y take() no son lo mismo.

El first() operador first() toma una función de predicate opcional y emite una notificación de error cuando ningún valor coincide cuando se completa la fuente.

Por ejemplo, esto emitirá un error:

 Rx.Observable.empty() .first() .subscribe(console.log, err => console.log('Error', err)); 

… tan bien como esto:

 Rx.Observable.range(1, 5) .first(val => val > 6) .subscribe(console.log, err => console.log('Error', err)); 

Si bien esto coincidirá con el primer valor emitido:

 Rx.Observable.range(1, 5) .first() .subscribe(console.log, err => console.log('Error', err)); 

Por otro lado, take(1) solo toma el primer valor y finaliza. No hay más lógica involucrada.

 Rx.Observable.range(1, 5) .take(1) .subscribe(console.log, err => console.log('Error', err)); 

Luego, con la fuente vacía Observable, no emitirá ningún error:

 Rx.Observable.empty() .take(1) .subscribe(console.log, err => console.log('Error', err)); 

Parece que en RxJS 5.2.0 .first () operador tiene un error ,

Debido a esa falla, .take (1) y .first () pueden comportarse de manera diferente si los está usando con el mapa de conmutación:

Con take (1) obtendrá el comportamiento esperado:

 var x = Rx.Observable.interval(1000) .do( x=> console.log("One")) .take(1) .switchMap(x => Rx.Observable.interval(1000)) .do( x=> console.log("Two")) .subscribe((x) => {}) // In console you will see: // One // Two // Two // Two // Two // etc... 

Pero con .first () obtendrá un comportamiento incorrecto:

 var x = Rx.Observable.interval(1000) .do( x=> console.log("One")) .first() .switchMap(x => Rx.Observable.interval(1000)) .do( x=> console.log("Two")) .subscribe((x) => {}) // In console you will see: // One // One // Two // One // Two // One // etc... 

Aquí enlace al codepen

Hay una diferencia realmente importante que no se menciona en ningún lado.

tomar (1) emite 1, completa, cancela la suscripción

first () emite 1, completa, pero no cancela la suscripción.

Significa que su observable aguas arriba todavía estará caliente después del primero (), que probablemente no sea el comportamiento esperado.

UPD: Esto se refiere a RxJS 5.2.0. Este problema ya puede estar solucionado.

    Intereting Posts