Rework lazy loading as js controlled fetches
This commit is contained in:
@@ -8,15 +8,101 @@
|
||||
// ============================================================
|
||||
// Gallery Thumbnails Module
|
||||
// ============================================================
|
||||
// Thumbnail loading now relies on native loading="lazy" attribute.
|
||||
// The browser handles deferred loading, connection limits, and
|
||||
// automatic cancellation on navigation.
|
||||
//
|
||||
// This module is kept as a stub for potential future enhancements.
|
||||
// Uses fetch() with AbortController to load thumbnails.
|
||||
// This allows true HTTP request cancellation on navigation,
|
||||
// unlike native loading="lazy" where queued requests block.
|
||||
Luxtools.GalleryThumbnails = (function () {
|
||||
var controller = null;
|
||||
var maxConcurrent = 4;
|
||||
var activeCount = 0;
|
||||
var queue = [];
|
||||
|
||||
function abortAll() {
|
||||
if (controller) {
|
||||
controller.abort();
|
||||
controller = null;
|
||||
}
|
||||
queue = [];
|
||||
activeCount = 0;
|
||||
}
|
||||
|
||||
function processQueue() {
|
||||
if (!controller) return;
|
||||
while (activeCount < maxConcurrent && queue.length > 0) {
|
||||
var img = queue.shift();
|
||||
loadThumb(img);
|
||||
}
|
||||
}
|
||||
|
||||
function loadThumb(img) {
|
||||
if (!controller) return;
|
||||
|
||||
var src = img.getAttribute('data-src');
|
||||
if (!src) {
|
||||
processQueue();
|
||||
return;
|
||||
}
|
||||
|
||||
activeCount++;
|
||||
|
||||
fetch(src, { signal: controller.signal })
|
||||
.then(function (response) {
|
||||
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||||
return response.blob();
|
||||
})
|
||||
.then(function (blob) {
|
||||
img.src = URL.createObjectURL(blob);
|
||||
img.removeAttribute('data-src');
|
||||
})
|
||||
.catch(function (err) {
|
||||
// Aborted or failed - ignore
|
||||
if (err.name !== 'AbortError') {
|
||||
// Keep data-src for potential retry, just log
|
||||
}
|
||||
})
|
||||
.finally(function () {
|
||||
activeCount--;
|
||||
processQueue();
|
||||
});
|
||||
}
|
||||
|
||||
function queueThumb(img) {
|
||||
if (!controller) return;
|
||||
if (!img.getAttribute('data-src')) return;
|
||||
if (img.getAttribute('data-queued') === '1') return;
|
||||
img.setAttribute('data-queued', '1');
|
||||
queue.push(img);
|
||||
processQueue();
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Native lazy loading handles everything.
|
||||
// No JavaScript intervention needed.
|
||||
var imgs = document.querySelectorAll(
|
||||
'div.luxtools-gallery img.luxtools-thumb[data-src], div.luxtools-imagebox img[data-src]'
|
||||
);
|
||||
if (!imgs || !imgs.length) return;
|
||||
|
||||
// Create abort controller for all requests
|
||||
controller = new AbortController();
|
||||
|
||||
// Abort all pending requests on navigation
|
||||
window.addEventListener('beforeunload', abortAll);
|
||||
window.addEventListener('pagehide', abortAll);
|
||||
|
||||
// Use IntersectionObserver to trigger loading
|
||||
if ('IntersectionObserver' in window) {
|
||||
var io = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
if (!entry.isIntersecting) return;
|
||||
queueThumb(entry.target);
|
||||
io.unobserve(entry.target);
|
||||
});
|
||||
}, { rootMargin: '200px' });
|
||||
|
||||
imgs.forEach(function (img) { io.observe(img); });
|
||||
} else {
|
||||
// Fallback: queue all
|
||||
imgs.forEach(queueThumb);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user