53 lines
1.8 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
},
|
|
);
|
|
} |