在显示图像之前确定图像是否缓存在浏览器中(内存或磁盘缓存)?
Determine if an image is cached in browser (either memory or disk cache) before displaying the image?
对于延迟加载可视化,我试图将淡入动画样式 class 仅应用于 尚未 在浏览器中缓存的图像。
要确定图像之前是否已加载并缓存在浏览器中,我们可以在如下函数中使用 HTMLImageElement.complete 属性:
const isImageCached = (imageSource) => {
let image = new Image();
image.src = imageSource;
const isCached = image.complete;
image.src = "";
image = null;
return isCached;
};
但是,在 Chrome 中,HTTP 缓存项位于 memory cache
或 disk cache
中。上述函数仅在图像位于 memory cache
时有效,如果图像位于 disk cache
则始终 return false。我认为这是因为内存在 0 毫秒时立即被访问,而磁盘缓存可能需要几毫秒才能被检索。
当您第一次打开并 运行 上面的脚本时,图像会淡入,因为它还没有缓存在浏览器中。当您通过按 "运行" 按钮重新 运行 脚本时,图像不会淡入,因为它现在缓存在 Chrome的memory cache
。如果内存缓存已被清除,则会出现此问题。该图像已被缓存,但现在它可能位于 disk cache
中,因此图像将淡入。
下面是 Chrome 开发人员工具的屏幕截图,详细说明了刷新页面 (disk cache
) 时的输出,然后重新 运行 脚本而不刷新页面 ( memory cache
):
在显示图像之前,是否可以在 JavaScript 中确定图像是否位于 HTTP 缓存中,memory cache
或 disk cache
?
const image = document.querySelector("img");
const marioSrc = "https://www.pinclipart.com/picdir/big/361-3619269_mario-16-bit-mario-bros-super-mario-world.png";
const isImageCached = (imageSource) => {
let image = new Image();
image.src = imageSource;
const result = image.complete;
image.src = "";
image = null;
return result;
};
if (!isImageCached(marioSrc)) {
image.classList.add("image-fade-in");
}
image.setAttribute("src", marioSrc);
:root {
margin: 0;
padding: 0;
}
body {
background-color: #444444;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow-y: hidden;
}
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
.image-fade-in {
animation: fade-in 1s ease-in-out;
}
<img />
需要设置特定的等待时间以确定图像是否在浏览器磁盘缓存中,虽然大多数情况下等待时间非常短(<5 毫秒),但该值可能会根据事件循环堆栈和硬件。
这可以通过竞速承诺来实现:加载图像与超时。
对于我的特定用例,如果图像加载时间低于 25 毫秒,我可以假设它已缓存,否则我将假设它从未加载并应用淡入样式。
const promiseTimeout = (ms, promise, timeoutMessage = null) => {
let timerID;
const timer = new Promise((resolve, reject) => {
timerID = setTimeout(() => reject(timeoutMessage), ms);
});
return Promise
.race([ promise, timer ])
.then((result) => {
clearTimeout(timerID);
return result;
});
};
const imageURL = "https://dummyimage.com/600x400/000/fff.png&text=a";
let image = new Image();
const imageComplete = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onError = () => reject(image);
image.src = imageURL;
});
promiseTimeout(25, imageComplete, "Not loaded from cache")
.then((result) => console.log("Loaded from cache:", result))
.catch((error) => {
image.src = "";
image = null;
console.log(error);
});
对于延迟加载可视化,我试图将淡入动画样式 class 仅应用于 尚未 在浏览器中缓存的图像。
要确定图像之前是否已加载并缓存在浏览器中,我们可以在如下函数中使用 HTMLImageElement.complete 属性:
const isImageCached = (imageSource) => {
let image = new Image();
image.src = imageSource;
const isCached = image.complete;
image.src = "";
image = null;
return isCached;
};
但是,在 Chrome 中,HTTP 缓存项位于 memory cache
或 disk cache
中。上述函数仅在图像位于 memory cache
时有效,如果图像位于 disk cache
则始终 return false。我认为这是因为内存在 0 毫秒时立即被访问,而磁盘缓存可能需要几毫秒才能被检索。
当您第一次打开并 运行 上面的脚本时,图像会淡入,因为它还没有缓存在浏览器中。当您通过按 "运行" 按钮重新 运行 脚本时,图像不会淡入,因为它现在缓存在 Chrome的memory cache
。如果内存缓存已被清除,则会出现此问题。该图像已被缓存,但现在它可能位于 disk cache
中,因此图像将淡入。
下面是 Chrome 开发人员工具的屏幕截图,详细说明了刷新页面 (disk cache
) 时的输出,然后重新 运行 脚本而不刷新页面 ( memory cache
):
在显示图像之前,是否可以在 JavaScript 中确定图像是否位于 HTTP 缓存中,memory cache
或 disk cache
?
const image = document.querySelector("img");
const marioSrc = "https://www.pinclipart.com/picdir/big/361-3619269_mario-16-bit-mario-bros-super-mario-world.png";
const isImageCached = (imageSource) => {
let image = new Image();
image.src = imageSource;
const result = image.complete;
image.src = "";
image = null;
return result;
};
if (!isImageCached(marioSrc)) {
image.classList.add("image-fade-in");
}
image.setAttribute("src", marioSrc);
:root {
margin: 0;
padding: 0;
}
body {
background-color: #444444;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow-y: hidden;
}
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
.image-fade-in {
animation: fade-in 1s ease-in-out;
}
<img />
需要设置特定的等待时间以确定图像是否在浏览器磁盘缓存中,虽然大多数情况下等待时间非常短(<5 毫秒),但该值可能会根据事件循环堆栈和硬件。
这可以通过竞速承诺来实现:加载图像与超时。
对于我的特定用例,如果图像加载时间低于 25 毫秒,我可以假设它已缓存,否则我将假设它从未加载并应用淡入样式。
const promiseTimeout = (ms, promise, timeoutMessage = null) => {
let timerID;
const timer = new Promise((resolve, reject) => {
timerID = setTimeout(() => reject(timeoutMessage), ms);
});
return Promise
.race([ promise, timer ])
.then((result) => {
clearTimeout(timerID);
return result;
});
};
const imageURL = "https://dummyimage.com/600x400/000/fff.png&text=a";
let image = new Image();
const imageComplete = new Promise((resolve, reject) => {
image.onload = () => resolve(image);
image.onError = () => reject(image);
image.src = imageURL;
});
promiseTimeout(25, imageComplete, "Not loaded from cache")
.then((result) => console.log("Loaded from cache:", result))
.catch((error) => {
image.src = "";
image = null;
console.log(error);
});