line-and-surface/src/services/ImageLoader.ts

80 lines
1.7 KiB
TypeScript

/**
* Global image loading queue service to prevent hitting browser connection limits
*/
// Configuration
const MAX_CONCURRENT_LOADS = 5;
// State
let activeLoads = 0;
const imageQueue: Array<{
element: HTMLImageElement;
onComplete: () => void;
}> = [];
/**
* Queue an image for loading, respecting the global concurrent loading limit
*/
export function queueImageForLoading(
element: HTMLImageElement,
onComplete?: () => void
) {
if (!element.dataset.src) {
console.warn("[ImageLoader] Element has no data-src attribute");
return;
}
// Add to queue
imageQueue.push({
element,
onComplete: onComplete || (() => {}),
});
// Try to process queue
processQueue();
}
/**
* Process the next items in the queue if we have capacity
*/
function processQueue() {
// Load more images if we have capacity and images in the queue
while (activeLoads < MAX_CONCURRENT_LOADS && imageQueue.length > 0) {
const next = imageQueue.shift();
if (next) {
loadImage(next.element, next.onComplete);
}
}
}
/**
* Internal function to handle the actual image loading
*/
function loadImage(element: HTMLImageElement, onComplete: () => void) {
// Increment active loads counter
activeLoads++;
const src = element.dataset.src;
console.debug(`[ImageLoader] Loading ${src}`);
// Start loading the image
element.src = src!;
// Handle load completion
const handleCompletion = () => {
activeLoads--;
onComplete();
processQueue();
};
// Set handlers
element.onload = () => {
console.debug(`[ImageLoader] Loaded ${src}`);
handleCompletion();
};
element.onerror = () => {
console.error(`[ImageLoader] Failed to load ${src}`);
handleCompletion();
};
}