javascript - 在显示图像之前确定图像是否缓存在浏览器中(内存或磁盘缓存)?

标签 javascript image google-chrome browser-cache http-caching

对于延迟加载可视化,我尝试仅将淡入动画样式类应用于尚未缓存在浏览器中的图像。

要确定图像之前是否已加载并缓存在浏览器中,我们可以使用 HTMLImageElement.complete 函数中的属性如下:

const isImageCached = (imageSource) => {

    let image = new Image();
    image.src = imageSource;

    const isCached = image.complete;
    image.src = "";
    image = null;
    
    return isCached;
};

但是,在 Chrome 中,HTTP 缓存项位于内存缓存磁盘缓存 中。上述函数仅在图像位于内存缓存中时有效,如果图像位于磁盘缓存中,则始终返回 false。我认为这是因为内存在 0 毫秒内立即被访问,而磁盘缓存可能需要长达几毫秒的时间才能被检索。

<强> Code Test (JSFiddle)

当您第一次打开并运行上述脚本时,图像会淡入,因为它尚未缓存在浏览器中。当您按“运行”按钮重新运行脚本时,图像不会淡入,因为它现在缓存在 Chrome 的内存缓存中。如果内存缓存已被清除,则会出现此问题。该图像已被缓存,但现在它可能位于磁盘缓存中,因此图像将会淡入。

下面是 Chrome 开发者工具的屏幕截图,详细说明了刷新页面时的输出(磁盘缓存),然后在不刷新页面的情况下重新运行脚本(内存缓存):

Chrome DevTools Screen Capture

在显示图像之前,是否可以在 JavaScript 中确定图像是否位于 HTTP 缓存(内存缓存磁盘缓存)中?

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 毫秒),但该值可能会根据事件循环而大幅波动堆栈和硬件。

这可以通过竞争 promise 来实现:加载图像与超时。

对于我的特定用例,如果图像在 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);
    });

关于javascript - 在显示图像之前确定图像是否缓存在浏览器中(内存或磁盘缓存)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62603102/

相关文章:

php - 使用 PHP 读取自定义图像标签元数据

android - 在 ListView 中显示图像 url

c# - 检查浏览器是chrome还是edge

google-chrome - 限制 Chrome 可用的 CPU 和资源

javascript - 我如何知道运行 Chrome 时的哪个脚本会导致打开新的弹出窗口?

javascript - 当到达页面的开头或结尾时,按键得到 “remembered”

javascript - 用于改进向 MVC3 Razor 页面添加 css 和脚本资源的工具/加速器

image - 叠加在带有名称的图像上

JavaScript getJSON 返回数组中的重复值

javascript - NodeJS 带有条件语句的顺序异步