Release v0.1.1 2026-07-10
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
export interface RateLimitedPublisher {
|
||||
request: () => void;
|
||||
cancel: () => void;
|
||||
dispose: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coalesces bursty state updates while preserving an immediate leading publish.
|
||||
* The trailing publish always contains current state because `publish` reads it
|
||||
* when the timer fires.
|
||||
*/
|
||||
export function createRateLimitedPublisher(
|
||||
publish: () => void,
|
||||
intervalMs: number,
|
||||
now: () => number = () => performance.now(),
|
||||
): RateLimitedPublisher {
|
||||
let lastPublishedAt = Number.NEGATIVE_INFINITY;
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
let disposed = false;
|
||||
|
||||
const run = () => {
|
||||
timer = null;
|
||||
if (disposed) return;
|
||||
lastPublishedAt = now();
|
||||
publish();
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
if (timer !== null) clearTimeout(timer);
|
||||
timer = null;
|
||||
};
|
||||
|
||||
return {
|
||||
request: () => {
|
||||
if (disposed) return;
|
||||
const remaining = intervalMs - (now() - lastPublishedAt);
|
||||
if (remaining <= 0) {
|
||||
if (timer !== null) clearTimeout(timer);
|
||||
run();
|
||||
return;
|
||||
}
|
||||
if (timer === null) timer = setTimeout(run, remaining);
|
||||
},
|
||||
cancel,
|
||||
dispose: () => {
|
||||
disposed = true;
|
||||
cancel();
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user