From bfe9100879b6475afa56dab8c27d29060befa60b Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 19 Apr 2023 12:56:01 +0200 Subject: [PATCH] MOBILE-4290 core: Make waitForImages cancellable --- src/core/services/utils/dom.ts | 69 ++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index 841a8195f..7a077c83b 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -59,6 +59,7 @@ import { CoreUserSupport } from '@features/user/services/support'; import { CoreErrorInfoComponent } from '@components/error-info/error-info'; import { CorePlatform } from '@services/platform'; import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2'; +import { CoreCancellablePromise } from '@classes/cancellable-promise'; /* * "Utils" service with helper functions for UI, DOM elements and HTML code. @@ -1918,32 +1919,62 @@ export class CoreDomUtilsProvider { * @param element The element to search in. * @returns Promise resolved with a boolean: whether there was any image to load. */ - async waitForImages(element: HTMLElement): Promise { + waitForImages(element: HTMLElement): CoreCancellablePromise { const imgs = Array.from(element.querySelectorAll('img')); - const promises: Promise[] = []; - let hasImgToLoad = false; - imgs.forEach((img) => { - if (img && !img.complete) { - hasImgToLoad = true; + if (imgs.length === 0) { + return CoreCancellablePromise.resolve(false); + } - // Wait for image to load or fail. - promises.push(new Promise((resolve) => { - const imgLoaded = (): void => { - resolve(); - img.removeEventListener('load', imgLoaded); - img.removeEventListener('error', imgLoaded); + let completedImages = 0; + let waitedForImages = false; + const listeners: WeakMap unknown> = new WeakMap(); + const imageCompleted = (resolve: (result: boolean) => void) => { + completedImages++; + + if (completedImages === imgs.length) { + resolve(waitedForImages); + } + }; + + return new CoreCancellablePromise( + resolve => { + for (const img of imgs) { + if (!img || img.complete) { + imageCompleted(resolve); + + continue; + } + + waitedForImages = true; + + // Wait for image to load or fail. + const imgCompleted = (): void => { + img.removeEventListener('load', imgCompleted); + img.removeEventListener('error', imgCompleted); + + imageCompleted(resolve); }; - img.addEventListener('load', imgLoaded); - img.addEventListener('error', imgLoaded); - })); - } - }); + img.addEventListener('load', imgCompleted); + img.addEventListener('error', imgCompleted); - await Promise.all(promises); + listeners.set(img, imgCompleted); + } + }, + () => { + imgs.forEach(img => { + const listener = listeners.get(img); - return hasImgToLoad; + if (!listener) { + return; + } + + img.removeEventListener('load', listener); + img.removeEventListener('error', listener); + }); + }, + ); } /**