Crea una suscripción única

182

Necesito crear una suscripción a una Observableque se elimine de inmediato cuando se llame por primera vez.

¿Hay algo como:

observable.subscribeOnce(func);

Mi caso de uso, estoy creando una suscripción en un controlador de ruta rápida y la suscripción se llama varias veces por solicitud.

Berkeley Martinez
fuente

Respuestas:

319

No estoy 100% seguro de lo que necesita, pero si solo desea observar el primer valor, use uno first()o take(1):

observable.first().subscribe(func);

nota: .take(1)y .first()ambos se anulan automáticamente cuando se cumple su condición

Actualización de RxJS 5.5+

Del comentario de Coderer .

import { first } from 'rxjs/operators'

observable
  .pipe(first())
  .subscribe(func);

Este es el por qué

Brandon
fuente
33
¿La suscripción se limpia automáticamente después?
Berkeley Martinez
50
Si lo hace Tome y primero anule la suscripción cuando se cumpla su condición.
Brandon el
20
¿Por qué la documentación no dice que elimina automáticamente la suscripción?
jzig
17
Es una regla general de RxJS que las suscripciones se eliminan cuando finaliza una secuencia observable. Eso significa que cualquier operador que "acorte" una secuencia (o la transforme en un tipo diferente de secuencia) se dará de baja de la secuencia fuente cuando se complete su operación. No estoy seguro de dónde o si esto se indica en la documentación.
Brandon
37
Si alguien viene a esto en 2018, realmente quieres saber de observable.pipe(first()).subscribe(func)dónde firstviene rxjs/operators.
Coderer
32

RxJS tiene la mejor documentación que he encontrado. Seguir el siguiente enlace lo llevará a casos de uso de mapeo de tablas extremadamente útiles para los operadores. Por ejemplo, bajo el "yo quiero tomar el primer valor" caso de uso son tres operadores: first, firstOrDefault, y sample.

Tenga en cuenta que si una secuencia observable se completa sin notificaciones, el firstoperador notifica a los suscriptores con un error, mientras que el firstOrDefaultoperador proporciona un valor predeterminado a los suscriptores.

búsqueda de casos de uso del operador

DetweilerRyan
fuente
3

Si desea llamar a un Observable solo una vez, significa que no va a esperar una transmisión de él. Por lo tanto, usar en toPromise()lugar de subscribe()sería suficiente en su caso, ya toPromise()que no necesita darse de baja.

M Fuat NUROĞLU
fuente
muy interesante, esto también significa que podemos hacer awaitlo promiseque lo hace único
Louie Almeda
@LouieAlmeda, ¿podría darnos un ejemplo de una línea?
Ado Ren
Hola @AdoRen, he expuesto la técnica en una respuesta aquí para ti, espero que te sirva de ayuda.
Louie Almeda
2

Para complementar la respuesta de @ Brandon , el uso first()o similar también es esencial para actualizar un en BehaviorSubjectfunción de su Observable. Por ejemplo (no probado):

var subject = new BehaviorSubject({1:'apple',2:'banana'});
var observable = subject.asObservable();

observable
  .pipe(
    first(), // <-- Ensures no stack overflow
    flatMap(function(obj) {
      obj[3] = 'pear';
      return of(obj);
    })
  )
  .subscribe(function(obj) {
    subject.next(obj);
  });
Andy
fuente
2

Versión limpia y conveniente

Ampliando la asombrosa respuesta de M Fuat NUROĞLU para convertir lo observable en una promesa, aquí está la versión muy conveniente.

const value = await observable.toPromise();

console.log(value)

¡Lo bueno de esto es que podemos usar ese valor como una variable normal sin introducir otro bloque anidado!

Esto es especialmente útil cuando necesita obtener múltiples valores de múltiples observables. Limpio y ordenado.

const content = await contentObservable.toPromise();
const isAuthenticated = await isAuthenticatedObservable.toPromise();

if(isAuthenticated){
   service.foo(content)
}

Por supuesto, tendrá que hacer que su función de contención asyncvaya a esta ruta. También puede hacer .thenla promesa si no desea que la función que contiene sea asíncrona

No estoy seguro de si hay compensaciones con este enfoque, no dude en hacérmelo saber en los comentarios para que estemos al tanto.

PD: si te gustó esta respuesta, no olvides votar la respuesta de M Fuat NUROĞLU también :)

Louie Almeda
fuente
0

Tuve una pregunta similar.

A continuación fue llamado incluso más tarde por diferentes cambiadores de estado. Como no quise.

function foo() {
    // this was called many times which was not needed
    observable.subscribe(func);
    changeObservableState("new value");
}

Decidí probar unsubscribe()después de suscribirme como a continuación.

function foo() {
    // this was called ONE TIME
    observable.subscribe(func).unsubscribe();
    changeObservableState("new value");
}

subscribe(func).unsubscribe();es como subscribeOnce(func).

Espero que eso también te haya ayudado.

MrHIDEn
fuente