Răsfoiți Sursa

reduce the number of messages sent to the bg page

Gildas 5 ani în urmă
părinte
comite
c6621bdfb4

+ 16 - 4
extension/lib/single-file/lazy/bg/lazy-timeout.js

@@ -27,20 +27,32 @@
 
 	"use strict";
 
+	const timeouts = new Map();
+
 	browser.runtime.onMessage.addListener((message, sender) => {
 		if (message.method == "singlefile.lazyTimeout.setTimeout") {
+			const previousTimeoutId = timeouts.get(message.type);
+			if (previousTimeoutId) {
+				clearTimeout(previousTimeoutId);
+			}
 			const timeoutId = setTimeout(async () => {
 				try {
-					await browser.tabs.sendMessage(sender.tab.id, { method: "singlefile.lazyTimeout.onTimeout", id: timeoutId });
+					timeouts.delete(message.type);
+					await browser.tabs.sendMessage(sender.tab.id, { method: "singlefile.lazyTimeout.onTimeout", type: message.type });
 				} catch (error) {
 					// ignored
 				}
 			}, message.delay);
-			return Promise.resolve(timeoutId);
+			timeouts.set(message.type, timeoutId);
+			return Promise.resolve({});
 		}
 		if (message.method == "singlefile.lazyTimeout.clearTimeout") {
-			clearTimeout(message.id);
-			return Promise.resolve({ id: message.id });
+			const timeoutId = timeouts.get(message.type);
+			if (timeoutId) {
+				clearTimeout(timeoutId);
+			}
+			timeouts.delete(message.type);
+			return Promise.resolve({});
 		}
 	});
 

+ 54 - 37
lib/single-file/processors/lazy/content/content-lazy-loader.js

@@ -33,6 +33,7 @@ this.singlefile.lib.processors.lazy.content.loader = this.singlefile.lib.process
 	const MutationObserver = window.MutationObserver;
 	const addEventListener = (type, listener, options) => window.addEventListener(type, listener, options);
 	const removeEventListener = (type, listener, options) => window.removeEventListener(type, listener, options);
+	const timeouts = new Map();
 
 	return {
 		process: async options => {
@@ -55,7 +56,7 @@ this.singlefile.lib.processors.lazy.content.loader = this.singlefile.lib.process
 	function process(options) {
 		const frames = singlefile.lib.processors.hooks.content.frames;
 		return new Promise(async resolve => { // eslint-disable-line  no-async-promise-executor
-			let timeoutId, idleTimeoutId, maxTimeoutId, loadingImages;
+			let loadingImages;
 			const pendingImages = new Set();
 			const observer = new MutationObserver(async mutations => {
 				mutations = mutations.filter(mutation => mutation.type == ATTRIBUTES_MUTATION_TYPE);
@@ -71,20 +72,21 @@ this.singlefile.lib.processors.lazy.content.loader = this.singlefile.lib.process
 					});
 					if (updated.length) {
 						loadingImages = true;
-						maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+						await deferForceLazyLoadEnd(observer, options, cleanupAndResolve);
 						if (!pendingImages.size) {
-							timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+							await deferLazyLoadEnd(observer, options, cleanupAndResolve);
 						}
 					}
 				}
 			});
-			idleTimeoutId = await setAsyncTimeout(() => {
+			await setAsyncTimeout("idleTimeout", () => {
 				if (!loadingImages) {
-					clearAsyncTimeout(timeoutId);
-					lazyLoadEnd(idleTimeoutId, observer, options, cleanupAndResolve);
+					clearAsyncTimeout("loadTimeout");
+					clearAsyncTimeout("maxTimeout");
+					lazyLoadEnd(observer, options, cleanupAndResolve);
 				}
-			}, options.loadDeferredImagesMaxIdleTime * 1.2);
-			maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+			}, options.loadDeferredImagesMaxIdleTime * 2);
+			await deferForceLazyLoadEnd(observer, options, cleanupAndResolve);
 			observer.observe(document, { subtree: true, childList: true, attributes: true });
 			if (frames) {
 				addEventListener(frames.LOAD_IMAGE_EVENT, onImageLoadEvent);
@@ -100,17 +102,19 @@ this.singlefile.lib.processors.lazy.content.loader = this.singlefile.lib.process
 
 			async function onImageLoadEvent(event) {
 				loadingImages = true;
-				maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+				await deferForceLazyLoadEnd(observer, options, cleanupAndResolve);
+				await deferLazyLoadEnd(observer, options, cleanupAndResolve);
 				if (event.detail) {
 					pendingImages.add(event.detail);
 				}
 			}
 
 			async function onImageLoadedEvent(event) {
-				maxTimeoutId = await deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, cleanupAndResolve);
+				await deferForceLazyLoadEnd(observer, options, cleanupAndResolve);
+				await deferLazyLoadEnd(observer, options, cleanupAndResolve);
 				pendingImages.delete(event.detail);
 				if (!pendingImages.size) {
-					timeoutId = await deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, cleanupAndResolve);
+					await deferLazyLoadEnd(observer, options, cleanupAndResolve);
 				}
 			}
 
@@ -125,50 +129,63 @@ this.singlefile.lib.processors.lazy.content.loader = this.singlefile.lib.process
 		});
 	}
 
-	async function deferLazyLoadEnd(timeoutId, idleTimeoutId, observer, options, resolve) {
-		await clearAsyncTimeout(timeoutId);
-		return setAsyncTimeout(() => lazyLoadEnd(idleTimeoutId, observer, options, resolve), options.loadDeferredImagesMaxIdleTime);
+	async function deferLazyLoadEnd(observer, options, resolve) {
+		await setAsyncTimeout("loadTimeout", () => lazyLoadEnd(observer, options, resolve), options.loadDeferredImagesMaxIdleTime);
 	}
 
-	function deferForceLazyLoadEnd(timeoutId, idleTimeoutId, maxTimeoutId, observer, options, resolve) {
-		clearAsyncTimeout(maxTimeoutId);
-		return setAsyncTimeout(() => {
-			clearAsyncTimeout(timeoutId);
-			lazyLoadEnd(idleTimeoutId, observer, options, resolve);
+	async function deferForceLazyLoadEnd(observer, options, resolve) {
+		await setAsyncTimeout("maxTimeout", async () => {
+			await clearAsyncTimeout("loadTimeout");
+			await lazyLoadEnd(observer, options, resolve);
 		}, options.loadDeferredImagesMaxIdleTime * 10);
 	}
 
-	function lazyLoadEnd(idleTimeoutId, observer, options, resolve) {
-		clearAsyncTimeout(idleTimeoutId);
+	async function lazyLoadEnd(observer, options, resolve) {
+		await clearAsyncTimeout("idleTimeout");
 		if (singlefile.lib.processors.hooks.content.frames) {
 			singlefile.lib.processors.hooks.content.frames.loadDeferredImagesEnd(options);
 		}
-		setAsyncTimeout(resolve, options.loadDeferredImagesMaxIdleTime / 2);
+		await setAsyncTimeout("endTimeout", async () => {
+			await clearAsyncTimeout("maxTimeout");
+			resolve();
+		}, options.loadDeferredImagesMaxIdleTime / 2);
 		observer.disconnect();
 	}
 
-	async function setAsyncTimeout(callback, delay) {
+	async function setAsyncTimeout(type, callback, delay) {
 		if (browser && browser.runtime && browser.runtime.sendMessage) {
-			const timeoutId = await browser.runtime.sendMessage({ method: "singlefile.lazyTimeout.setTimeout", delay });
-			const timeoutCallback = message => {
-				if (message.method == "singlefile.lazyTimeout.onTimeout" && message.id == timeoutId) {
-					browser.runtime.onMessage.removeListener(timeoutCallback);
-					callback();
-					return Promise.resolve({});
-				}
-			};
-			browser.runtime.onMessage.addListener(timeoutCallback);
-			return timeoutId;
+			if (!timeouts.get(type)) {
+				timeouts.set(type, callback);
+				await browser.runtime.sendMessage({ method: "singlefile.lazyTimeout.setTimeout", type, delay });
+				const timeoutCallback = message => {
+					if (message.method == "singlefile.lazyTimeout.onTimeout" && message.type == type) {
+						browser.runtime.onMessage.removeListener(timeoutCallback);
+						callback();
+						return Promise.resolve({});
+					}
+				};
+				timeouts.delete(type, callback);
+				browser.runtime.onMessage.addListener(timeoutCallback);
+			}
 		} else {
-			return window.setTimeout(callback, delay);
+			const timeoutId = timeouts.get(type);
+			if (timeoutId) {
+				window.clearTimeout(timeoutId);
+			}
+			timeouts.set(type, callback);
+			window.setTimeout(callback, delay);
 		}
 	}
 
-	async function clearAsyncTimeout(timeoutId) {
+	async function clearAsyncTimeout(type) {
 		if (browser && browser.runtime && browser.runtime.sendMessage) {
-			await browser.runtime.sendMessage({ method: "singlefile.lazyTimeout.clearTimeout", id: timeoutId });
+			await browser.runtime.sendMessage({ method: "singlefile.lazyTimeout.clearTimeout", type });
 		} else {
-			return window.clearTimeout(timeoutId);
+			const previousTimeoutId = timeouts.get(type);
+			timeouts.delete(type);
+			if (previousTimeoutId) {
+				window.clearTimeout(previousTimeoutId);
+			}
 		}
 	}