3 votos

Usando rxjs para limitar la velocidad de llamadas de retorno

Estoy consumiendo una API en la que registro un callback que ocurre frecuentemente.

function myCallback(event) {
  // hacer cosas con el evento, algo computacionalmente intenso
}

const algo = createSomething({
  onSomethingHappened: myCallback
})

Me gustaría limitar la frecuencia con la que este callback se dispara, probablemente usando throttle. Este proyecto utiliza Angular que incluye rx. ¿Cómo puedo adaptar mi código para que myCallback se limite a 300ms usando rx?

Tengo entendimiento básico de cómo funcionan los observables pero ha sido un poco confuso descifrar cómo la interfaz del callback se convertiría a una interfaz observable.

(editado a medida que lleguen respuestas)

3voto

Andrei Gătej Puntos 6391

Creo que puedes usar fromEventPattern:

let something;

const src$ = fromEventPattern(
  handler => (something = createSomething({ onSomethingHappened: handler })),
);

src$.pipe(
  throttleTime(300),
  map(args => myCallback(args))
);

Nota: esto asume que myCallback es una operación síncrona.

El primer argumento pasado a fromEventPattern es el addHandler. También puede tener el removeHandler, donde puedes poner tu lógica de limpieza (por ejemplo: liberación de memoria, nulificación de valores, etc).


Para tener una mejor comprensión de qué es handler y por qué se usa ahí, veamos cómo está implementado fromEventPattern:

return new Observable(subscriber => {
  const handler = (...e: T[]) => subscriber.next(e.length === 1 ? e[0] : e);

  let retValue: any;
  try {
    retValue = addHandler(handler);
  } catch (err) {
    subscriber.error(err);
    return undefined;
  }

  if (!isFunction(removeHandler)) {
    return undefined;
  }

  // Esta función devuelta se llamará cuando el observable
  // se desuscriba. Es decir, en la desuscripción manual, en el completo o en el error.
  return () => removeHandler(handler, retValue) ;
});

Fuente.

Como puedes ver, a través de handler, puedes permitir que el observable devuelto emita algo cuando sea el momento.

1voto

Yasser Nascimento Puntos 1124

Solo puedes conectar el operador throttleTime a un flujo fromEvent.

import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';

const mouseMove$ = fromEvent(document, 'mousemove');
mouseMove$.pipe(throttleTime(300)).subscribe(...callback);

1voto

sdgluck Puntos 9082

No tengo mucha familiaridad con RxJS pero algo como lo siguiente es posible.

Échale un vistazo en StackBlitz: https://stackblitz.com/edit/rxjs-ijzehs.

import { Subject, interval } from 'rxjs';
import { throttle } from 'rxjs/operators';

function myCallback(v) {
  // hacer cosas con el evento, algo computacionalmente intensivo
  console.log("valor recibido", v)
}

const o$ = new Subject()

o$.pipe(throttle(v => interval(300))).subscribe(myCallback)

const algo = crearAlgo({
  enAlgoOcurrio: v => {
    o$.next(v)
  }
})

function crearAlgo({ enAlgoOcurrio }) {
  let i = 0
  setInterval(() => {
    console.log("llamando a enAlgoOcurrio")
    enAlgoOcurrio(i++)
  }, 100)
}

0voto

satanTime Puntos 6886

Puedes usar un simple Subject

function myCallback(event) {
  // haz cosas con el evento, algo intensivo computacionalmente
}

// el sujeto presenta todas las emisiones.
const subject = new Subject();
const subscription = subject.pipe( 
  throttle(300), // ahora lo limitamos como querías.
).subscribe(myCallback);

const something = createSomething({
  onSomethingHappened: e => subject.next(e), // usando el sujeto en lugar de una devolución de llamada.
})

// subscription.unsubscribe(); // una vez que no lo necesitamos.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X