La semana pasada respondí una pregunta de RxJS en la que entablé una discusión con otro miembro de la comunidad acerca de: "¿Debería crear una suscripción para cada efecto secundario específico o debería tratar de minimizar las suscripciones en general?" Quiero saber qué metodología utilizar en términos de un enfoque de aplicación reactiva completa o cuándo cambiar de una a otra. Esto me ayudará a mí, y quizás a otros, a evitar discusiones incómodas.
Información de configuración
- Todos los ejemplos están en TypeScript
- Para un mejor enfoque en la pregunta, no se deben usar ciclos de vida / constructores para suscripciones y para mantener en el marco no relacionados
- Imagínese: las suscripciones se agregan en constructor / lifecycle init
- Imagínese: darse de baja se realiza en el ciclo de vida destruir
¿Qué es un efecto secundario (muestra angular)
- Actualización / Entrada en la interfaz de usuario (por ejemplo
value$ | async
) - Salida / flujo ascendente de un componente (p
@Output event = event$
. Ej. ) - Interacción entre diferentes servicios en diferentes jerarquías.
Caso de uso ejemplar:
- Dos funciones:
foo: () => void; bar: (arg: any) => void
- Dos fuentes observables:
http$: Observable<any>; click$: Observable<void>
foo
se llama después dehttp$
emitido y no necesita ningún valorbar
se llama después declick$
emitir, pero necesita el valor actual dehttp$
Caso: cree una suscripción para cada efecto secundario específico
const foo$ = http$.pipe(
mapTo(void 0)
);
const bar$ = http$.pipe(
switchMap(httpValue => click$.pipe(
mapTo(httpValue)
)
);
foo$.subscribe(foo);
bar$.subscribe(bar);
Caso: minimizar las suscripciones en general
http$.pipe(
tap(() => foo()),
switchMap(httpValue => click$.pipe(
mapTo(httpValue )
)
).subscribe(bar);
Mi propia opinión en resumen
Puedo entender el hecho de que las suscripciones hacen que los paisajes Rx sean más complejos al principio, porque tienes que pensar en cómo los suscriptores deberían afectar la tubería o no, por ejemplo (comparte tu observable o no). Pero cuanto más separe su código (cuanto más se enfoque: qué sucede cuándo), más fácil será mantener (probar, depurar, actualizar) su código en el futuro. Con eso en mente, siempre creo una única fuente observable y una única suscripción para cualquier efecto secundario en mi código. Si dos o más efectos secundarios que tengo se desencadenan exactamente por la misma fuente observable, entonces comparto mi observable y me suscribo a cada efecto secundario individualmente, porque puede tener diferentes ciclos de vida.
fuente
takeUntil
en combinación con una función que se llama desdengOnDestroy
. Es un chiste que añade esto a la tubería:takeUntil(componentDestroyed(this))
. stackoverflow.com/a/60223749/5367916Si optimizar suscripciones es su objetivo final, ¿por qué no ir al extremo lógico y simplemente seguir este patrón general:
La ejecución exclusiva de efectos secundarios al tocar y la activación con combinación significa que solo tiene una suscripción.
Una razón para no hacer esto es que está neutralizando mucho de lo que hace que RxJS sea útil. Cuál es la capacidad de componer transmisiones observables y suscribirse / darse de baja de las transmisiones según sea necesario.
Yo diría que sus observables deben estar compuestos lógicamente, y no contaminados o confundidos en nombre de la reducción de suscripciones. ¿Debería el efecto foo estar lógicamente unido al efecto de barra? ¿Uno necesita el otro? ¿Es posible que alguna vez no quiera disparar foo cuando se emite http $? ¿Estoy creando un acoplamiento innecesario entre funciones no relacionadas? Estas son todas las razones para evitar ponerlas en una secuencia.
Todo esto ni siquiera considera el manejo de errores, que es más fácil de administrar con varias suscripciones IMO
fuente