你如何在 Javascript 中缓存图像

IT技术 javascript jquery image caching browser-cache
2021-01-13 09:37:51

我和我的朋友正在开发一个网站,我们希望在该网站上缓存某些图像,以便将来更快地显示它们。我有两个主要问题:

  1. 你如何缓存图像?
  2. 图像被缓存后如何使用?(并且只是为了验证,如果图像缓存在页面 A 上,可以从缓存中调用它以在页面 B 上使用它,对吗?)

此外,有可能设置时,图像的缓存版本将到期?

如果包含一个示例和/或指向进一步描述此内容的页面的链接,将不胜感激。

我们可以使用原始 Javascript 或 jQuery 版本。

6个回答

一旦图像以任何方式加载到浏览器中,它将在浏览器缓存中,并且下次使用时加载速度会更快,无论该使用是在当前页面中还是在任何其他页面中,只要图像是在浏览器缓存过期之前使用。

因此,要预缓存图像,您要做的就是将它们加载到浏览器中。如果你想预缓存一堆图像,最好用 javascript 来做,因为当从 javascript 完成时它通常不会阻止页面加载。你可以这样做:

function preloadImages(array) {
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    var list = preloadImages.list;
    for (var i = 0; i < array.length; i++) {
        var img = new Image();
        img.onload = function() {
            var index = list.indexOf(this);
            if (index !== -1) {
                // remove image from the array once it's loaded
                // for memory consumption reasons
                list.splice(index, 1);
            }
        }
        list.push(img);
        img.src = array[i];
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);

可以根据需要多次调用此函数,并且每次都会向预缓存添加更多图像。

一旦通过 javascript 像这样预加载图像,浏览器会将它们保存在其缓存中,您只需在其他地方(在您的网页中)引用普通 URL,浏览器将从其缓存中获取该 URL,而不是通过网络。

最终,随着时间的推移,浏览器缓存可能会填满并丢弃一段时间未使用的最旧的东西。所以最终,图像将从缓存中清除,但它们应该在那里停留一段时间(取决于缓存有多大以及其他浏览完成了多少)。每次实际再次预加载图像或在网页中使用图像时,它都会自动刷新它们在浏览器缓存中的位置,因此它们不太可能从缓存中刷新。

浏览器缓存是跨页面的,因此它适用于加载到浏览器中的任何页面。因此,您可以在站点的一个位置进行预缓存,然后浏览器缓存将适用于站点上的所有其他页面。


如上所述进行预缓存时,图像是异步加载的,因此它们不会阻止页面的加载或显示。但是,如果您的页面有很多自己的图像,这些预缓存图像可能会与页面中显示的图像争夺带宽或连接。通常,这不是一个明显的问题,但在连接速度较慢的情况下,这种预缓存可能会减慢主页的加载速度。如果最后加载预加载图像是可以的,那么您可以使用该函数的一个版本,该版本会等到所有其他页面资源都已加载后才开始预加载。

function preloadImages(array, waitForOtherResources, timeout) {
    var loaded = false, list = preloadImages.list, imgs = array.slice(0), t = timeout || 15*1000, timer;
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    if (!waitForOtherResources || document.readyState === 'complete') {
        loadNow();
    } else {
        window.addEventListener("load", function() {
            clearTimeout(timer);
            loadNow();
        });
        // in case window.addEventListener doesn't get called (sometimes some resource gets stuck)
        // then preload the images anyway after some timeout time
        timer = setTimeout(loadNow, t);
    }

    function loadNow() {
        if (!loaded) {
            loaded = true;
            for (var i = 0; i < imgs.length; i++) {
                var img = new Image();
                img.onload = img.onerror = img.onabort = function() {
                    var index = list.indexOf(this);
                    if (index !== -1) {
                        // remove image from the array once it's loaded
                        // for memory consumption reasons
                        list.splice(index, 1);
                    }
                }
                list.push(img);
                img.src = imgs[i];
            }
        }
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"], true);
preloadImages(["url99.jpg", "url98.jpg"], true);
在此示例中,您将为每个 url 创建一个新的 Image 对象。如果你在循环之外设置 img 变量并只更新 src,它应该具有相同的效果并减少资源
2021-03-26 09:37:51
它似乎无需等待即可在较新版本的浏览器上运行,但您说得很好。我将不得不在一些较旧的浏览器上试用它以查看它的兼容性:)
2021-03-29 09:37:51
@cadlac - 不需要。我更新了代码以Image()在图像加载完成后从列表中删除元素。等待图像加载完成更安全。
2021-03-29 09:37:51
@cadlac - 但要确定浏览器实际上会下载和缓存每个图像,您必须等到一个图像完成下载后再设置新的 .src 属性。否则浏览器可能会停止先前的下载并且永远不会成功缓存它。
2021-03-30 09:37:51
我添加了另一个版本的脚本,等待其他文档资源加载完毕,这样图像的预加载不会与可见页面资源的加载竞争带宽。
2021-04-09 09:37:51

正如@Pointy 所说,您不使用 javascript 缓存图像,浏览器会这样做。所以这可能是你所要求的,也可能不是......但你可以使用javascript预加载图像。通过将您想要预加载的所有图像放入一个数组并将该数组中的所有图像放入隐藏的 img 元素中,您可以有效地预加载(或缓存)这些图像。

var images = [
'/path/to/image1.png',
'/path/to/image2.png'
];

$(images).each(function() {
var image = $('<img />').attr('src', this);
});
是否可以在一页上预加载图像(不显示),然后在下一页上显示?
2021-04-01 09:37:51
据我所知,如果您在一个页面上预加载图像,它将被输入到浏览器缓存中,然后在任何其他页面上显示得更快。如果这是错误的,请有人纠正我。
2021-04-10 09:37:51

现在,谷歌推荐了一种新技术来缓存和改进您的图像渲染过程:

  1. 包含 JavaScript Lazysizes 文件:lazysizes.js
  2. 将文件添加到您要使用的 html 文件中: <script src="lazysizes.min.js" async></script>
  3. lazyload添加到您的图像中: <img data-src="images/flower3.png" class="lazyload" alt="">

即使您的问题是“使用 javascript”,您也可以使用prefetch链接标签属性来预加载任何资产。在撰写本文时(2016 年 8 月 10 日),Safari 不支持它,但几乎在其他任何地方都支持它:

<link rel="prefetch" href="(url)">

有关此处支持的更多信息:http : //caniuse.com/#search=prefetch

请注意,IE 9,10 未列在caniuse矩阵中,因为 Microsoft 已停止对它们的支持。

因此,如果您真的坚持使用 javascript,您也可以使用 jquery 将这些元素动态添加到您的页面中 ;-)

不错不错不错不错!
2021-03-17 09:37:51

添加答案的完整性:使用 HTML 预加载

<link rel="preload" href="bg-image-wide.png" as="image">

存在其他预加载功能,但没有一个像以下那样适合<link rel="preload">

  • <link rel="prefetch">浏览器已支持很长时间,但它旨在预取将在下一次导航/页面加载中使用的资源(例如,当您转到下一页时)。这很好,但对当前页面没有用!此外,浏览器会给预取资源的优先级低于预加载资源——当前页面比下一个更重要。有关更多详细信息,请参阅链接预取常见问题解答
  • <link rel="prerender">在后台呈现指定的网页,如果用户导航到它,则加速其加载。由于可能浪费用户带宽,Chrome 将预渲染视为 NoState 预取。
  • <link rel="subresource"> 不久前在 Chrome 中受支持,旨在解决与预加载相同的问题,但它有一个问题:无法确定项目的优先级(因为当时不存在),所以它们都以相当低的优先级获取。

有许多基于脚本的资源加载器,但它们对浏览器的 fetch 优先级队列没有任何权力,并且受到几乎相同的性能问题的影响。

来源:https : //developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content