packages/designer/src/builtin-simulator/utils/throttle.ts (79 lines of code) (raw):
const useRAF = typeof requestAnimationFrame === 'function';
// eslint-disable-next-line @typescript-eslint/ban-types
export function throttle(func: Function, delay: number) {
let lastArgs: any;
let lastThis: any;
let result: any;
let timerId: number | undefined;
let lastCalled: number | undefined;
let lastInvoked = 0;
function invoke(time: number) {
const args = lastArgs;
const thisArg = lastThis;
lastArgs = undefined;
lastThis = undefined;
lastInvoked = time;
result = func.apply(thisArg, args);
return result;
}
function startTimer(pendingFunc: any, wait: number): number {
if (useRAF) {
return requestAnimationFrame(pendingFunc);
}
return setTimeout(pendingFunc, wait) as any;
}
function leadingEdge(time: number) {
lastInvoked = time;
timerId = startTimer(timerExpired, delay);
return invoke(time);
}
function shouldInvoke(time: number) {
const timeSinceLastCalled = time - lastCalled!;
const timeSinceLastInvoked = time - lastInvoked;
return (
lastCalled === undefined ||
timeSinceLastCalled >= delay ||
timeSinceLastCalled < 0 ||
timeSinceLastInvoked >= delay
);
}
function remainingWait(time: number) {
const timeSinceLastCalled = time - lastCalled!;
const timeSinceLastInvoked = time - lastInvoked;
return Math.min(delay - timeSinceLastCalled, delay - timeSinceLastInvoked);
}
function timerExpired() {
const time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
timerId = startTimer(timerExpired, remainingWait(time));
}
function trailingEdge(time: number) {
timerId = undefined;
if (lastArgs) {
return invoke(time);
}
lastArgs = undefined;
lastThis = undefined;
return result;
}
function debounced(this: any, ...args: any[]) {
const time = Date.now();
const isInvoking = shouldInvoke(time);
lastArgs = args;
lastThis = this;
lastCalled = time;
if (isInvoking) {
if (timerId === undefined) {
return leadingEdge(lastCalled);
}
timerId = startTimer(timerExpired, delay);
return invoke(lastCalled);
}
if (timerId === undefined) {
timerId = startTimer(timerExpired, delay);
}
return result;
}
return debounced;
}