@base-ui/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
84 lines (83 loc) • 2.48 kB
JavaScript
/**
* Manages concurrent fetching with a queue system.
* Tracks request lifecycle through queued → pending states
* and limits concurrency to prevent overwhelming the server.
*/
export class RequestQueue {
pendingRequests = new Map();
queuedRequests = new Map();
constructor(options) {
this.fetchFn = options.fetchFn;
this.maxConcurrentRequests = options.maxConcurrentRequests ?? Infinity;
this.getKeyId = options.getKeyId ?? String;
}
/**
* Returns the next `count` entries to process from the queue.
* Default is FIFO (oldest first). Subclasses can override for different ordering.
*/
pickEntries(count) {
const result = [];
const iterator = this.queuedRequests.entries();
for (let i = 0; i < count; i += 1) {
const {
value
} = iterator.next();
result.push(value);
}
return result;
}
processQueue = async () => {
if (this.queuedRequests.size === 0 || this.pendingRequests.size >= this.maxConcurrentRequests) {
return;
}
const loopLength = Math.min(this.maxConcurrentRequests - this.pendingRequests.size, this.queuedRequests.size);
if (loopLength === 0) {
return;
}
const fetchPromises = [];
for (const [keyId, key] of this.pickEntries(loopLength)) {
this.queuedRequests.delete(keyId);
this.pendingRequests.set(keyId, key);
fetchPromises.push(this.fetchFn(key).catch(() => {
this.pendingRequests.delete(keyId);
}));
}
await Promise.all(fetchPromises);
if (this.queuedRequests.size > 0) {
await this.processQueue();
}
};
queue = async keys => {
for (const key of keys) {
const keyId = this.getKeyId(key);
if (!this.pendingRequests.has(keyId)) {
this.queuedRequests.set(keyId, key);
}
}
await this.processQueue();
};
setRequestSettled = async key => {
const keyId = this.getKeyId(key);
this.pendingRequests.delete(keyId);
await this.processQueue();
};
clear = () => {
this.queuedRequests.clear();
this.pendingRequests.clear();
};
clearPendingRequest = async key => {
const keyId = this.getKeyId(key);
this.pendingRequests.delete(keyId);
await this.processQueue();
};
getRequestStatus = key => {
const keyId = this.getKeyId(key);
if (this.pendingRequests.has(keyId)) {
return 'pending';
}
if (this.queuedRequests.has(keyId)) {
return 'queued';
}
return 'unknown';
};
}