/** * 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(); }; }