91

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

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

另外,是否可以设置图像的缓存版本何时到期?

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

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

4

10 回答 10

142

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

因此,要预缓存图像,您只需将它们加载到浏览器中即可。如果您想预先缓存一堆图像,最好使用 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);
于 2012-04-20T04:30:42.350 回答
13

as @Pointy said you don't cache images with javascript, the browser does that. so this may be what you are asking for and may not be... but you can preload images using javascript. By putting all of the images you want to preload into an array and putting all of the images in that array into hidden img elements, you effectively preload (or cache) the images.

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

$(images).each(function() {
var image = $('<img />').attr('src', this);
});
于 2012-04-20T04:13:23.107 回答
5

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

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

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

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

市面上有许多基于脚本的资源加载器,但它们对浏览器的获取优先级队列没有任何控制权,并且会遇到几乎相同的性能问题。

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

于 2019-09-13T19:15:37.717 回答
5

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

  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="">
于 2019-10-29T15:37:37.493 回答
4

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

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

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

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

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

于 2016-08-10T12:39:36.973 回答
3

There are a few things you can look at:

Pre-loading your images
Setting a cache time in an .htaccess file
File size of images and base64 encoding them.

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

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

There are a couple different thoughts for base64 encoding, some say that the http requests bog down bandwidth, while others say that the "perceived" loading is better. I'll leave this up in the air.

于 2012-04-20T04:13:51.967 回答
1

对于通过 JS 异步预加载图像,我有类似的答案。动态加载它们与正常加载它们相同。他们会缓存。

至于缓存,您无法控制浏览器,但可以通过服务器进行设置。如果您需要按需加载一个真正新鲜的资源,您可以使用缓存破坏技术来强制加载一个新资源。

于 2012-04-20T04:18:26.863 回答
1

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

我的例子:

我的主页上有一个带有 4 张图片的旋转横幅,滑块等待 2 秒,然后 javascript 加载下一张图片,等待 2 秒,等等。

这些图像具有唯一的 url,每当我修改它们时它们就会发生变化,因此它们会获得缓存标头,这些标头将在浏览器中缓存一年。

max-age: 31536000, public

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

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

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

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

如果这是 Chrome Devtools 中的一个错误,我真的很惊讶我还没有人注意到这一点。;)

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

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

于 2017-03-07T17:04:08.673 回答
0

Yes, the browser caches images for you, automatically.

You can, however, set an image cache to expire. Check out this Stack Overflow questions and answer:

Cache Expiration On Static Images

于 2012-04-20T04:15:49.577 回答
0

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

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

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

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

    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例如, 您可以从Document Ready中调用它

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

于 2017-08-28T07:56:17.433 回答