que observables example entre ejemplo comunicacion componentes angular rxjs rxjs5 angularfire2 angular2-observables

observables - Angular 2 usando RxJS-take(1) vs first()



que es un observable en angular (5)

Consejo: Use solo first() si:

  • Considera que cero elementos emitidos son una condición de error (por ejemplo, completar antes de emitir) Y si hay una probabilidad mayor de 0% de error, lo maneja con gracia
  • O bien, Usted sabe al 100% que la fuente observable emitirá 1 o más elementos (por lo que nunca puede arrojar) .

Si hay cero emisiones y no lo está manejando explícitamente (con catchError ), ese error se propagará, posiblemente causará un problema inesperado en otro lugar y puede ser bastante difícil de rastrear, especialmente si proviene de un usuario final.

Estás más seguro usando take(1) en su mayor parte siempre que:

  • Estás de acuerdo con que take(1) no emita nada si la fuente se completa sin una emisión.
  • No necesita usar un predicado en línea (por ejemplo, first(x => x > 10) )

Nota: Puede usar un predicado con take(1) como este: .pipe( filter(x => x > 10), take(1) ) . No hay ningún error con esto si nada es mayor que 10.

¿Qué pasa con single()

Si desea ser aún más estricto y no permitir dos emisiones, puede usar single() que errores si hay cero o más de 2 emisiones . Nuevamente, necesitaría manejar los errores en ese caso.

Consejo: Single puede ocasionalmente ser útil si desea asegurarse de que su cadena observable no esté haciendo un trabajo adicional, como llamar a un servicio http dos veces y emitir dos observables. Agregar single al final de la tubería le permitirá saber si cometió tal error. Lo estoy usando en un ''corredor de tareas'' donde pasas una tarea observable que solo debería emitir un valor, así que paso la respuesta a través de single(), catchError() para garantizar un buen comportamiento.

¿Por qué no usar siempre first() lugar de take(1) ?

aka. ¿Cómo puede causar potencialmente más errores?

Si tiene un observable que toma algo de un servicio y luego lo canaliza first() , debería estar bien la mayor parte del tiempo. Pero si alguien viene a deshabilitar el servicio por cualquier razón, y lo cambia para emitir of(null) o NEVER , cualquier operador first() descendente comenzaría a arrojar errores.

Ahora me doy cuenta de que puede ser exactamente lo que quieres, de ahí que esto sea solo un consejo. El operador first me atrajo porque sonaba un poco menos `` torpe '''' que take(1) pero debe tener cuidado con el manejo de errores si alguna vez existe la posibilidad de que la fuente no se emita. Sin embargo, dependerá completamente de lo que estés haciendo.

Si tiene un valor predeterminado (constante):

Considere también .pipe(defaultIfEmpty(42), first()) si tiene un valor predeterminado que debe usarse si no se emite nada. Por supuesto, esto no generaría un error porque first siempre recibiría un valor.

Tenga en cuenta que defaultIfEmpty solo se activa si la secuencia está vacía, no si el valor de lo que se emite es null .

Encontré poca implementación de Auth Guards que usa take(1) . En mi proyecto, usé 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> | 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) } }


Aquí hay tres observables A , B y C con diagramas de mármol para explorar la diferencia entre los operadores first , take y single :

* Leyenda :
--o-- valor
----! error
----| terminación

Juega con él en https://thinkrx.io/rxjs/first-vs-take-vs-single/ .

Ya teniendo todas las respuestas, quería agregar una explicación más visual.

Espero que ayude a alguien


Hay una diferencia realmente importante que no se menciona en ninguna parte.

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

first () emite 1, completa, pero no se da de baja.

Significa que su observable ascendente seguirá caliente después de first (), lo que probablemente no sea un comportamiento esperado.

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


Los operadores first() y take(1) 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:

import { EMPTY, range } from ''rxjs''; import { first, take } from ''rxjs/operators''; EMPTY.pipe( first(), ).subscribe(console.log, err => console.log(''Error'', err));

... tan bien como esto:

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

Si bien esto coincidirá con el primer valor emitido:

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

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

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

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

EMPTY.pipe( take(1), ).subscribe(console.log, err => console.log(''Error'', err));

Enero de 2019: actualizado para RxJS 6


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

Debido a ese error, .take(1) y .first() pueden comportarse de manera bastante diferente si los está usando con switchMap :

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 the 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í hay un enlace a codepen