que example ejemplo angular rxjs observable

example - return observable angular 4



Obtenga el valor actual de Observable sin suscribirse(solo desea valor una vez) (3)

El título lo dice todo de verdad. ¿Cómo puedo obtener el valor actual de un Observable sin suscribirme? Solo quiero el valor actual una vez y no valores nuevos, ya que están llegando ...


Necesitas usar BehaviorSubject ,

  • BehaviorSubject es similar a ReplaySubject, excepto que solo recuerda la última publicación.
  • BehaviorSubject también requiere que le proporcione un valor predeterminado de T. Esto significa que todos los suscriptores recibirán un valor inmediatamente (a menos que ya esté completado).

Le dará el valor más reciente publicado por el observable.

BehaviorSubject proporciona una propiedad getter llamada value para obtener el valor más reciente que se le pasa.

DEMO DE PLUNKER

  • En este ejemplo, el valor ''a'' se escribe en la consola:

//Declare a Subject, you''ll need to provide a default value. var subject: BehaviorSubject<string> = new BehaviorSubject("a");

USO:

console.log(subject.value); // will print the current value


No estoy seguro si esto es lo que estás buscando. Probablemente escriba ese tema de comportamiento en un servicio. Declárelo como privado y exponga solo el valor que ha establecido. Algo como esto

@Injectable({ providedIn: ''root'' }) export class ConfigService { constructor(private bname:BehaviorSubject<String>){ this.bname = new BehaviorSubject<String>("currentvalue"); } getAsObservable(){ this.bname.asObservable(); } }

De esta manera, los usuarios externos solo tienen acceso para suscribirse al comportamientoSujeto y puede establecer el valor deseado en el servicio.


Respuesta rápida:

... Solo quiero el valor actual una vez y no valores nuevos, ya que están llegando ...

Seguirá usando subscribe , pero con pipe(take(1)) para que le dé un solo valor.

p.ej. myObs$.pipe(take(1)).subscribe(value => alert(value));

Consulte también: Comparación entre first() , take(1) o single()

Respuesta más larga:

La regla general es que solo debe obtener un valor de un observable con subscribe()

(o tubería asíncrona si se usa Angular)

BehaviorSubject definitivamente tiene su lugar, y cuando comencé con RxJS solía hacer bs.value() para obtener un valor. A medida que sus transmisiones RxJS se propagan a lo largo de toda su aplicación (¡y eso es lo que quiere!), Será cada vez más difícil hacerlo. A menudo, verás que .asObservable() usa para "ocultar" el tipo subyacente para evitar que alguien use .value() , y al principio esto parecerá malo, pero comenzarás a apreciar por qué se hace con el tiempo. Además, tarde o temprano necesitará un valor de algo que no sea un BehaviorSubject y no habrá una manera de hacerlo así.

Sin embargo, volviendo a la pregunta original. Especialmente si no quieres ''hacer trampa'' usando un BehaviorSubject .

El mejor enfoque es usar subscribe para obtener un valor.

obs$.pipe(take(1)).subscribe(value => { ....... })

O

obs$.pipe(first()).subscribe(value => { ....... })

La diferencia entre estos dos first() será un error si el flujo ya se ha completado y take(1) no emitirá ningún observable si el flujo se ha completado o no tiene un valor disponible de inmediato.

Nota: esto se considera una mejor práctica incluso si está utilizando un BehaviorSubject.

Sin embargo, si prueba el código anterior, el "valor" del observable se "atorará" dentro del cierre de la función de suscripción y es posible que lo necesite en el ámbito actual. Una forma de evitar esto si realmente tienes que hacerlo es esta:

const obsValue = undefined; const sub = obs$.pipe(take(1)).subscribe(value => obsValue = value); sub.unsubscribe(); // we will only have a value here if it was IMMEDIATELY available alert(obsValue);

Es importante tener en cuenta que la llamada de suscripción anterior no espera un valor. Si no hay nada disponible de inmediato, nunca se llamará a la función de suscripción, y coloco la llamada para cancelar la suscripción deliberadamente para evitar que ''aparezca más tarde''.

Así que no solo esto se ve muy torpe: no funcionará para algo que no está disponible de inmediato, como un valor de resultado de una llamada http, sino que de hecho funcionará con un tema de comportamiento (o más importante, algo que es * upstream y se sabe que es un BehaviorSubject **, o combineLatest que toma dos valores de BehaviorSubject ). Y definitivamente no vayas a hacer (obs$ as BehaviorSubject) - ugh!

Este ejemplo anterior todavía se considera una mala práctica en general, es un desastre. Solo hago el estilo de código anterior si quiero ver si un valor está disponible de inmediato y poder detectar si no lo está.

Mejor acercamiento

Usted está mucho mejor si puede mantener todo lo más observable el mayor tiempo posible, y solo suscribirse cuando realmente necesite el valor, y no intente "extraer" un valor en un ámbito de contenido que es lo que estoy haciendo. encima.

p.ej. Digamos que queremos hacer un informe de nuestros animales, si su zoológico está abierto. Podría pensar que quiere el valor ''extraído'' de zooOpen$ esta manera:

Mal camino

zooOpen$: Observable<boolean> = of(true); // is the zoo open today? bear$: Observable<string> = of(''Beary''); lion$: Observable<string> = of(''Liony''); runZooReport() { // we want to know if zoo is open! // this uses the approach described above const zooOpen: boolean = undefined; const sub = this.zooOpen$.subscribe(open => zooOpen = open); sub.unsubscribe(); // ''zooOpen'' is just a regular boolean now if (zooOpen) { // now take the animals, combine them and subscribe to it combineLatest(this.bear$, this.lion$).subscribe(([bear, lion]) => { alert(''Welcome to the zoo! Today we have a bear called '' + bear + '' and a lion called '' + lion); }); } else { alert(''Sorry zoo is closed today!''); } }

Entonces, ¿por qué es esto tan malo?

  • ¿Qué pasa si zooOpen$ proviene de un servicio web? ¿Cómo funcionará el ejemplo anterior? En realidad, no importa lo rápido que sea su servidor: ¡nunca obtendría un valor con el código anterior si zooOpen$ fuera un http observable!
  • ¿Qué pasa si desea utilizar este informe ''fuera'' de esta función. Ahora ha bloqueado la alert en este método. ¡Si tiene que usar el informe en otro lugar, tendría que duplicar esto!

Buen camino

En lugar de intentar acceder al valor en su función, considere en su lugar una función que crea un nuevo Observable y que ni siquiera se suscribe a él.

En cambio, devuelve un nuevo observable que puede ser consumido ''afuera''.

Al mantener todo como observable y usar switchMap para tomar decisiones, puede crear nuevos observables que pueden ser la fuente de otros observables.

getZooReport() { return this.zooOpen$.pipe(switchMap(zooOpen => { if (zooOpen) { return combineLatest(this.bear$, this.lion$).pipe(map(([bear, lion] => { // this is inside ''map'' so return a regular string return "Welcome to the zoo! Today we have a bear called '' + bear + '' and a lion called '' + lion; } ); } else { // this is inside ''switchMap'' so *must* return an observable return of(''Sorry the zoo is closed today!''); } }); }

Lo anterior crea un nuevo observable para que podamos ejecutarlo en otros lugares y canalizarlo más si lo deseamos.

const zooReport$ = this.getZooReport(); zooReport$.pipe(take(1)).subscribe(report => { alert(''Todays report: '' + report); }); // or take it and put it into a new pipe const zooReportUpperCase$ = zooReport$.pipe(map(report => report.toUpperCase()));

Tenga en cuenta lo siguiente:

  • No me suscribo hasta que sea absolutamente necesario, en este caso, está fuera de la función.
  • El observable de ''conducción'' es zooOpen$ y que usa switchMap para ''cambiar'' a un observable diferente que es, en última instancia, el que devuelve getZooReport() .
  • La forma en que esto funciona si zooOpen$ cambia, entonces cancela todo y comienza nuevamente dentro del primer switchMap . Lea sobre switchMap para más sobre eso.
  • Nota: El código dentro de switchMap debe devolver un nuevo observable. Puedes hacer uno rápidamente con of(''hello'') - o devolver otro observable como combineLatest .
  • Del mismo modo: el map solo debe devolver una cadena normal.

Tan pronto comencé a hacer una nota mental para no suscribirme hasta que tuve que hacerlo, de repente empecé a escribir un código mucho más productivo, flexible, más limpio y fácil de mantener.

Otra nota final: si utiliza este enfoque con Angular, podría tener el informe del zoológico anterior sin una sola subscribe al usar | async tubería | async . Este es un gran ejemplo de "no suscribirse hasta que TENGA que" el director en la práctica.

// in your angular .ts file for a component const zooReport$ = this.getZooReport();

y en su plantilla:

<pre> {{ zooReport$ | async }} </pre>

Véase también mi respuesta aquí:

https://.com/a/54209999/16940

Tampoco se menciona arriba para evitar confusiones:

  • tap() puede ser útil a veces para "obtener el valor de un observable". Si no está familiarizado con ese operador lea en él. RxJS usa ''tuberías'' y un operador de tap() es una forma de ''conectarse a la tubería'' para ver qué hay allí.