[英]How can I wait until a web page has loaded and all controls have been populated before executing my javascript?
[英]Wait until all images on the page have been loaded
我想等到沒有更多圖片下載:
const waitForImages = async () => {
const cleanupHandler = new Set();
const images = document.querySelectorAll("img");
console.log("wait for images", images.length);
await Promise.all(
Array.from(images).map((image) =>
new Promise<void>((resolve) => {
if (image.complete) {
return resolve();
}
const timeout = setTimeout(() => {
console.log(image, "timed out");
resolve();
}, 500);
const cleanup = () => {
clearTimeout(timeout);
image.removeEventListener("load", imageLoadingDone);
image.removeEventListener("error", imageLoadingDone);
cleanupHandler.delete(cleanup);
};
cleanupHandler.add(cleanup);
const imageLoadingDone = () => {
console.log(image, "done");
cleanup();
resolve();
};
image.addEventListener("load", imageLoadingDone);
image.addEventListener("error", imageLoadingDone);
})
)
);
console.log("all images loaded");
cleanupHandler.forEach((cleanup) => cleanup());
}
該代碼運行良好。 不幸的是,一旦頁面上有一個隱藏的<img loading="lazy">
load
事件就永遠不會被觸發。 (參見HTML 圖片元素加載)
有什么辦法可以跳過那些沒有開始下載的loading="lazy"
圖像嗎?
嘗試這個
Array.from(images).filter((image) => image.loading !== "lazy").map(...)
我找到了一個解決方案,但我仍然希望有一個不那么復雜的解決方案:
/**
* Wait until all images are downloaded and encoded.
*/
export const waitForImages = async () => {
// Get only images in view - this is a Workaround for lazy loading images
const images = Array.from(await getAllImagesIntersectingViewport());
const imageLoadPromisses = Array.from(images).map(
(image) =>
new Promise<void>((resolve) => {
if (image.complete) {
return resolve();
}
// fallback timeout to prevent freezing the entire test
const timeout = setTimeout(() => {
console.log("timeout", image);
resolve();
}, 2000);
const cleanup = () => {
clearTimeout(timeout);
image.removeEventListener("load", imageLoadingDone);
image.removeEventListener("error", imageLoadingDone);
};
const imageLoadingDone = () => {
cleanup();
image
.decode()
.catch(() => {
/* ignore decoding erros */
})
.then(resolve);
};
image.addEventListener("load", imageLoadingDone);
image.addEventListener("error", imageLoadingDone);
})
);
// wait until all images are loaded
await Promise.all(imageLoadPromisses);
return images;
};
/**
* Get all images that are currently inside the viewport
*/
const getAllImagesIntersectingViewport = async () => {
const intersectingImages = new Set<HTMLImageElement>();
const images = document.querySelectorAll("img");
if (images.length) {
let observer: IntersectionObserver | undefined;
await new Promise<void>((resolve) => {
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (
entry.isIntersecting &&
entry.target instanceof HTMLImageElement
) {
intersectingImages.add(entry.target);
}
});
resolve();
});
observer = imageObserver;
images.forEach((image) => imageObserver.observe(image));
});
if (observer) {
observer.disconnect();
}
}
return intersectingImages;
};
這個想法太簡單了,以至於我可能誤解了問題(如果是的話,請道歉)。
這個想法是通過直接將 function 中的"img"
選擇器替換為以下內容,將查詢選擇器限制為那些缺少loading="lazy"
屬性的圖像:
"img:not([loading='lazy'])"
以下代碼段包含七個圖像元素,其中四個具有loading="lazy"
屬性。 使用上述選擇器引用的 html 集合包含 3 個項目,對應於 3 個“正常”圖像元素。
const images = document.querySelectorAll("img:not([loading='lazy'])"); console.log(images.length);
<img src="path/1.png" loading="lazy" /> <img src="path/2.png" /> <img src="path/3.png" loading="lazy" /> <img src="path/4.png" /> <img src="path/5.png" /> <img src="path/6.png" loading="lazy" /> <img src="path/7.png" loading="lazy" />
從 這里抓取
我們將在幕后克隆每個圖像(即不將其渲染到 DOM),然后監聽它的加載。 新腳本可能如下所示:
$(document).ready(function () {
// Images loaded is zero because we're going to process a new set of images.
var imagesLoaded = 0;
// Total images is still the total number of <img> elements on the page.
var totalImages = $("img").length;
// Step through each image in the DOM, clone it, attach an onload event
// listener, then set its source to the source of the original image. When
// that new image has loaded, fire the imageLoaded() callback.
$("img").each(function (idx, img) {
$("<img>").on("load", imageLoaded).attr("src", $(img).attr("src"));
});
// Do exactly as we had before -- increment the loaded count and if all are
// loaded, call the allImagesLoaded() function.
function imageLoaded() {
imagesLoaded++;
if (imagesLoaded == totalImages) {
allImagesLoaded();
}
}
function allImagesLoaded() {
console.log("ALL IMAGES LOADED");
}
});
如果只想跳過它們,您可以通過加載屬性來簡單地過濾圖像
const images = document.querySelectorAll("img").filter(img => img.loading !== "lazy");
這樣你的代碼就不會等待惰性圖像。 如果您想要下載所有圖像,您可以通過編程方式將加載設置為“自動”,但我相信這不是你的情況
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.