balabola-vk/src/utilities/throttledQueue.ts

53 lines
1.8 KiB
TypeScript

export function throttledQueue(
maxRequestsPerInterval: number,
interval: number,
evenlySpaced = false,
) {
if (evenlySpaced) {
interval = interval / maxRequestsPerInterval;
maxRequestsPerInterval = 1;
}
const queue: Array<() => Promise<void>> = [];
let lastIntervalStart = 0;
let numRequestsPerInterval = 0;
let timeout: NodeJS.Timeout | undefined;
const dequeue = () => {
const intervalEnd = lastIntervalStart + interval;
const now = Date.now();
if (now < intervalEnd) {
timeout !== undefined && clearTimeout(timeout);
timeout = setTimeout(dequeue, intervalEnd - now);
return;
}
lastIntervalStart = now;
numRequestsPerInterval = 0;
for (const callback of queue.splice(0, maxRequestsPerInterval)) {
numRequestsPerInterval++;
void callback();
}
if (queue.length) {
timeout = setTimeout(dequeue, interval);
} else {
timeout = undefined;
}
};
return <Return = unknown>(fn: () => Promise<Return> | Return): Promise<Return> => new Promise<Return>(
(resolve, reject) => {
const callback = () => Promise.resolve().then(fn).then(resolve).catch(reject);
const now = Date.now();
if (timeout === undefined && (now - lastIntervalStart) > interval) {
lastIntervalStart = now;
numRequestsPerInterval = 0;
}
if (numRequestsPerInterval++ < maxRequestsPerInterval) {
void callback();
} else {
queue.push(callback);
if (timeout === undefined) {
timeout = setTimeout(dequeue, lastIntervalStart + interval - now);
}
}
},
);
}