如何在Javascript中缓存图像

时间:2012-04-20 04:07:07

标签: javascript jquery image caching browser-cache

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

  1. 如何缓存图像?
  2. 缓存后如何使用图像? (并且只是为了验证,如果图像缓存在页面A上,可以从缓存中调用它以在页面B上使用它,对吗?)
  3. 此外,是否可以在图像的缓存版本到期时设置

    如果包含了进一步描述此内容的页面的示例和/或链接,将非常感激。

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

10 个答案:

答案 0 :(得分:112)

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

因此,要预先缓存图像,您只需将它们加载到浏览器中即可。如果你想预先处理一堆图像,最好用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);

答案 1 :(得分:10)

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

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

$(images).each(function() {
var image = $('<img />').attr('src', this);
});

答案 2 :(得分:2)

您可以查看以下几点:

预装图像
在.htaccess文件中设置缓存时间
图像的文件大小和base64编码它们。

预压: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

缓存: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

对于base64编码有一些不同的想法,有人说http请求会降低带宽,而另一些人则认为“感知”加载更好。我会把它留在空中。

答案 3 :(得分:1)

我有一个similar answer用于通过JS进行异步预加载图像。动态加载它们与正常加载它们相同。他们会缓存。

对于缓存,您无法控制浏览器,但可以通过服务器进行设置。如果您需要按需加载真正新鲜的资源,可以使用cache buster technique强制加载新资源。

答案 4 :(得分:1)

即使您的问题是&#34;使用javascript&#34;,您也可以使用链接标记的prefetch属性来预加载任何资产。在撰写本文时(2016年8月10日),它在Safari中不受支持,但几乎无处不在:

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

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

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

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

答案 5 :(得分:1)

我使用类似的技术来延迟加载图像,但不禁注意到Javascript在首次加载时无法访问浏览器缓存。

我的例子:

我的主页上有一个旋转的横幅,有4个图像,滑块等待2秒,比javascript加载下一个图像,等待2秒等等。

这些图片具有唯一的网址,只要我修改它们就会发生变化,因此它们会在浏览器中缓存一年的缓存标题。

max-age: 31536000, public

现在,当我打开Chrome Devtools并确保de'Adapable cache'选项未激活并首次加载页面时(清除缓存后),所有图像都会获取并具有200状态。在横幅中的所有图像的完整循环之后,网络请求停止并且使用高速缓存的图像。

现在,当我进行常规刷新或转到子页面并单击后退时,缓存中的图像似乎被忽略。我希望在Chrome devtools的Network选项卡中看到一条灰色消息“来自磁盘缓存”。相反,我看到请求每两秒传递一次绿色状态圈而不是灰色,我看到数据正在传输,所以我得到的印象是,根本没有从javascript访问缓存。它只是在每次加载页面时获取图像。

因此,无论图像的缓存策略如何,每个主页请求都会触发4个请求。

考虑到上述内容和大多数网络服务器和浏览器现在支持的新http2标准,我认为最好停止使用延迟加载,因为http2几乎会同时加载所有图像。

如果这是Chrome Devtools中的一个错误,那真的很让我感到意外。 ;)

如果这是真的,使用延迟加载只会增加带宽的使用。

如果我错了,请纠正我。 :)

答案 6 :(得分:0)

是的,浏览器会自动为您缓存图像。

但是,您可以将图像缓存设置为过期。查看此Stack Overflow问题并回答:

Cache Expiration On Static Images

答案 7 :(得分:0)

我总是喜欢使用Konva JS: Image Events中提到的示例来加载图片。

  1. 您需要将图像网址列表作为对象或数组,例如:

    var sources = { lion: '/assets/lion.png', monkey: '/assets/monkey.png' };

  2. 定义函数定义,它在参数列表中接收图像URL列表和回调函数,因此当它完成加载图像时,您可以在您的网页上开始执行:

  3.     function loadImages(sources, callback) {
                    var images = {};
                    var loadedImages = 0;
                    var numImages = 0;
                    for (var src in sources) {
                        numImages++;
                    }
                    for (var src in sources) {
                        images[src] = new Image();
                        images[src].onload = function () {
                            if (++loadedImages >= numImages) {
                                callback(images);
                            }
                        };
                        images[src].src = sources[src];
                    }
                }

    1. 最后,您需要调用该函数。您可以从 jQuery 文档就绪
    2. 中调用它

      $(document).ready(function (){ loadImages(sources, buildStage); });

答案 8 :(得分:0)

添加完整的答案:HTML预加载

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

还存在其他预加载功能,但没有一个比<link rel="preload">合适的目的:

  • <link rel="prefetch">已在浏览器中长期支持, 但这是为了预取将在 下一导航/页面加载(例如,当您转到下一页时)。这个 很好,但是对于当前页面没有用!此外,浏览器 与预加载资源相比,预取资源的优先级较低– 当前页面比下一页更重要。有关更多详细信息,请参见Link prefetching FAQ
  • <link rel="prerender">呈现指定的 网页在后台,如果用户导航,则可以加快其加载速度 对此。由于可能浪费用户带宽,因此Chrome 而是将prerender视为NoState预取。
  • Chrome之前支持
  • <link rel="subresource">,当时 打算解决与预加载相同的问题,但是有一个问题: 没有办法确定项目的优先级(因为没有 当时存在),因此它们的优先级都较低。

那里有许多基于脚本的资源加载器,但是它们没有控制浏览器的获取优先级队列,并且会遇到很多相同的性能问题。

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

答案 9 :(得分:0)

如今,有一个新的technique suggested by google可以缓存和改善您的图像渲染过程:

  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="">