Selaa lähdekoodia

improved detection of images loading

Gildas 7 vuotta sitten
vanhempi
sitoutus
7f07abf3b9
2 muutettua tiedostoa jossa 38 lisäystä ja 20 poistoa
  1. 5 6
      lib/hooks/hooks-frame.js
  2. 33 14
      lib/lazy/content/content-lazy-loader.js

+ 5 - 6
lib/hooks/hooks-frame.js

@@ -109,8 +109,8 @@ this.hooksFrame = this.hooksFrame || (() => {
 						const image = new Image(...arguments);
 						const result = new Image(...arguments);
 						result.__defineSetter__("src", function (value) {
-							dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT));
 							image.src = value;
+							dispatchEvent(new CustomEvent(LOAD_IMAGE_EVENT, { detail: image.src }));
 						});
 						result.__defineGetter__("src", function () {
 							return image.src;
@@ -122,8 +122,8 @@ this.hooksFrame = this.hooksFrame || (() => {
 						result.__defineGetter__("srcset", function () {
 							return image.srcset;
 						});
-						image.onload = image.onprogress = image.onloadend = image.onerror = event => {
-							dispatchEvent(new CustomEvent(IMAGE_LOADED_EVENT));
+						image.onload = image.onloadend = image.onerror = event => {
+							dispatchEvent(new CustomEvent(IMAGE_LOADED_EVENT, { detail: image.src }));
 							result.dispatchEvent(new UIEvent(event.type, event));
 						};
 						return result;
@@ -142,10 +142,9 @@ this.hooksFrame = this.hooksFrame || (() => {
 				dispatchEvent(new UIEvent("scroll"));
 				document.documentElement.style.setProperty("transform", transform, transformPriority);
 				document.documentElement.style.setProperty("transform-origin", transformOrigin, transformOriginPriority);
-			} else {
-				dispatchEvent(new UIEvent("resize"));
-				dispatchEvent(new UIEvent("scroll"));
 			}
+			dispatchEvent(new UIEvent("resize"));
+			dispatchEvent(new UIEvent("scroll"));
 			const docBoundingRect = document.documentElement.getBoundingClientRect();
 			Array.from(observers).forEach(([intersectionObserver, observer]) => {
 				const rootBoundingRect = observer.options.root && observer.options.root.getBoundingClientRect();

+ 33 - 14
lib/lazy/content/content-lazy-loader.js

@@ -30,12 +30,9 @@ this.lazyLoader = this.lazyLoader || (() => {
 
 	function process(options) {
 		return new Promise(async resolve => {
-			let timeoutId, loadingImages;
-			setAsyncTimeout(() => {
-				clearAsyncTimeout(timeoutId);
-				lazyLoadEnd(idleTimeoutId, observer, cleanupAndResolve);
-			}, options.loadDeferredImagesMaxIdleTime * 5);
-			const observer = new MutationObserver(async mutations => {
+			let timeoutId, idleTimeoutId, maxTimeoutId, loadingImages, observer, pendingImages = new Set();
+			maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+			observer = new MutationObserver(async mutations => {
 				mutations = mutations.filter(mutation => mutation.type == ATTRIBUTES_MUTATION_TYPE);
 				if (mutations.length) {
 					const updated = mutations.filter(mutation => {
@@ -48,32 +45,46 @@ this.lazyLoader = this.lazyLoader || (() => {
 					});
 					if (updated.length) {
 						loadingImages = true;
-						timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+						maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+						if (!pendingImages.size) {
+							timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+						}
 					}
 				}
 			});
 			observer.observe(document, { subtree: true, childList: true, attributes: true });
-			const idleTimeoutId = await setAsyncTimeout(() => {
+			idleTimeoutId = await setAsyncTimeout(() => {
 				if (!loadingImages) {
 					clearAsyncTimeout(timeoutId);
 					lazyLoadEnd(idleTimeoutId, observer, cleanupAndResolve);
 				}
 			}, options.loadDeferredImagesMaxIdleTime * 1.2);
+			addEventListener(hooksFrame.LOAD_IMAGE_EVENT, onImageLoadEvent);
+			addEventListener(hooksFrame.IMAGE_LOADED_EVENT, onImageLoadedEvent);
 			if (typeof hooksFrame != "undefined") {
 				hooksFrame.loadDeferredImagesStart();
 			}
-			addEventListener(hooksFrame.LOAD_IMAGE_EVENT, onImageEvent);
-			addEventListener(hooksFrame.IMAGE_LOADED_EVENT, onImageEvent);
 
-			async function onImageEvent() {
+			async function onImageLoadEvent(event) {
 				loadingImages = true;
-				timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+				maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+				if (event.detail) {
+					pendingImages.add(event.detail);
+				}
+			}
+
+			async function onImageLoadedEvent(event) {
+				maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+				pendingImages.delete(event.detail);
+				if (!pendingImages.size) {
+					timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+				}
 			}
 
 			function cleanupAndResolve(value) {
 				observer.disconnect();
-				removeEventListener(hooksFrame.LOAD_IMAGE_EVENT, onImageEvent);
-				removeEventListener(hooksFrame.IMAGE_LOADED_EVENT, onImageEvent);
+				removeEventListener(hooksFrame.LOAD_IMAGE_EVENT, onImageLoadEvent);
+				removeEventListener(hooksFrame.IMAGE_LOADED_EVENT, onImageLoadedEvent);
 				resolve(value);
 			}
 		});
@@ -84,6 +95,14 @@ this.lazyLoader = this.lazyLoader || (() => {
 		return setAsyncTimeout(async () => await lazyLoadEnd(idleTimeoutId, observer, resolve), options.loadDeferredImagesMaxIdleTime);
 	}
 
+	async function deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, resolve) {
+		clearAsyncTimeout(maxTimeoutId);
+		return setAsyncTimeout(() => {
+			clearAsyncTimeout(timeoutId);
+			lazyLoadEnd(idleTimeoutId, observer, resolve);
+		}, options.loadDeferredImagesMaxIdleTime * 10);
+	}
+
 	function lazyLoadEnd(idleTimeoutId, observer, resolve) {
 		clearAsyncTimeout(idleTimeoutId);
 		if (typeof hooksFrame != "undefined") {