Reputation: 1353
I am consuming an API in which I register a callback that occurs frequently.
function myCallback(event) {
// do things with event, something computationally intensive
}
const something = createSomething({
onSomethingHappened: myCallback
})
I'd like to limit the rate at which this callback fires, probably using throttle. This project uses Angular which bundles rx. How can I adapt my code so myCallback
it throttled at 300ms using rx?
I have a basic grasp on how observables work but it's been a bit confusing to figure out how the callback interface would convert to observable interface.
(edited as answers come)
Upvotes: 3
Views: 1788
Reputation: 13539
You can use a simple Subject
function myCallback(event) {
// do things with event, something computationally intensive
}
// subject presents all emits.
const subject = new Subject();
const subscription = subject.pipe(
throttle(300), // now we limit it as you wanted.
).subscribe(myCallback);
const something = createSomething({
onSomethingHappened: e => subject.next(e), // using subject instead of callback.
})
// subscription.unsubscribe(); // once we don't need it.
Upvotes: 1
Reputation: 27217
I'm not really familiar with RxJS but something like the following is possible.
Check it out on StackBlitz: https://stackblitz.com/edit/rxjs-ijzehs.
import { Subject, interval } from 'rxjs';
import { throttle } from 'rxjs/operators';
function myCallback(v) {
// do things with event, something computationally intensive
console.log("got value", v)
}
const o$ = new Subject()
o$.pipe(throttle(v => interval(300))).subscribe(myCallback)
const something = createSomething({
onSomethingHappened: v => {
o$.next(v)
}
})
function createSomething({ onSomethingHappened }) {
let i = 0
setInterval(() => {
console.log("calling onSomethingHappened")
onSomethingHappened(i++)
}, 100)
}
Upvotes: 1
Reputation: 11934
I think you can use fromEventPattern
:
let something;
const src$ = fromEventPattern(
handler => (something = createSomething({ onSomethingHappened: handler })),
);
src$.pipe(
throttleTime(300),
map(args => myCallback(args))
);
Note: this assumed that myCallback
is a synchronous operation.
The first argument passed to fromEventPattern
is the addHandler
. It can also have the removeHandler
, where you can put your teardown logic(e.g: releasing from memory, nulling out values etc).
In order to get a better understanding of what is handler
and why is it used there, let's see how fromEventPattern
is implemented:
return new Observable<T | T[]>(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;
}
// This returned function will be called when the observable
// is unsubscribed. That is, on manual unsubscription, on complete, or on error.
return () => removeHandler(handler, retValue) ;
});
As you can see, through handler
, you can let the returned observable when it's time to emit something.
Upvotes: 3
Reputation: 1381
You can just pipe the operator throttleTime
to a fromEvent
stream.
import { fromEvent } from 'rxjs';
import { throttleTime } from 'rxjs/operators';
const mouseMove$ = fromEvent(document, 'mousemove');
mouseMove$.pipe(throttleTime(300)).subscribe(...callback);
Upvotes: 1