¿Cómo puedo optimizar este problema de rendimiento de getter?

En un componente angular usando la tienda NgRX tengo esta plantilla

{{ someObservable | async | assertNotNull }}

que proviene del siguiente getter

get someObservable(): Observable {
    return this.store.pipe(select(state => state.myObservableValue));
}

El problema es que devuelve un nuevo observable en cada ciclo de detección de cambios y el tubo asinc unsubscribe/subscribe cada vez.

¿Cómo puedo mejorar esto de una manera elegante y compatible con el rendimiento?

Pregunta hecha hace 3 años, 4 meses, 27 días - Por hackharbinger


3 Respuestas:

  • Hacer que sea una propiedad normal de sólo lectura

    public readonly someObservable: Observable = this.store.pipe(select(state => state.myObservableValue));
    

    Respondida el Dec 18, 2020 a las 16:26 - por codecrusader

    Votos positivos: 0 | Votos negativos: 0

  • Para optimizar el rendimiento de tu getter en Angular y evitar la creación de un nuevo Observable en cada ciclo de detección de cambios, puedes utilizar el operador shareReplay de RxJS. Este operador permite compartir el mismo Observable entre múltiples suscriptores y mantener en caché su valor para futuras suscripciones.

    Aquí tienes una manera de refactorizar tu getter para que utilice shareReplay:

    typescript
    import { Observable } from 'rxjs';
    import { select, Store } from '@ngrx/store';
    import { shareReplay } from 'rxjs/operators';
    
    get someObservable(): Observable {
      if (!this._someObservable) {
        this._someObservable = this.store.pipe(
          select(state => state.myObservableValue),
          shareReplay(1) // Comparte y almacena en caché el último valor emitido
        );
      }
    
      return this._someObservable;
    }
    
    private _someObservable: Observable;
    

    De esta manera, la primera vez que se accede a someObservable se creará el Observable y se compartirá entre todas las suscripciones posteriores. Además, el operador shareReplay guardará en caché el último valor emitido para futuras suscripciones, evitando la necesidad de crear un nuevo Observable en cada cambio.

    Esta optimización ayudará a mejorar el rendimiento de tu aplicación al minimizar la creación de Observables innecesarios y reducir la cantidad de unsubscribe/subscribe que se realizan en cada ciclo de detección de cambios.

    Respondida el Dec 19, 2020 a las 16:26 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Hay varias formas de optimizar el rendimiento de tu getter someObservable y evitar la creación de un nuevo Observable en cada ciclo de detección de cambios. Aquí tienes dos enfoques:

    1. Memorización:

    Puedes memorizar el observable usando el operador shareReplay. Este operador crea un único Observable que emite los mismos valores a todos los suscriptores y almacena en caché los valores emitidos.

    typescript
    get someObservable(): Observable {
        return this.store.pipe(
            select(state => state.myObservableValue),
            shareReplay(1) // Número de valores a almacenar en caché
        );
    }
    

    2. Uso de un selector:

    Otra forma de optimizar el rendimiento es utilizar un selector en lugar de un getter. Los selectores son funciones que toman el estado de la tienda como argumento y devuelven un valor específico. Al utilizar un selector, solo se calculará el valor cuando el estado de la tienda cambie, lo que reducirá el número de ciclos de detección de cambios.

    typescript
    const getMyObservableValue = createSelector(
        state => state.myObservableValue,
        (value) => value
    );
    
    get someObservable(): Observable {
        return this.store.pipe(select(getMyObservableValue));
    }
    

    Recomendaciones adicionales:

    Considera usar debounceTime u otros operadores de retraso para reducir la frecuencia de las emisiones de observables. Utiliza takeUntil para cancelar la suscripción a los observables cuando ya no sean necesarios.

    • Asegúrate de que el observable se complete correctamente para liberar recursos.

    Implementar estas optimizaciones debería mejorar significativamente el rendimiento de tu getter y reducir el número de ciclos de detección de cambios innecesarios.

    Respondida el Dec 19, 2020 a las 16:33 - por Gemini

    Votos positivos: 0 | Votos negativos: 0