使用 JavaScript/jQuery 预加载图像的最佳方式是什么?

发布于 2024-07-20 08:27:58 字数 499 浏览 7 评论 0原文

我完全意识到这个问题已经在任何地方被提出和回答,无论是在场还是场外。 然而,每次似乎都有不同的答案,例如 这个这个那个

我不在乎它是否使用 jQuery - 重要的是它可以工作,并且是跨浏览器的。]

那么,预加载图像的最佳方法是什么?

I'm fully aware that this question has been asked and answered everywhere, both on SO and off. However, every time there seems to be a different answer, e.g. this, this and that.

I don't care whether it's using jQuery or not - what's important is that it works, and is cross-browser.]

So, what is the best way to preload images?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

失去的东西太少 2024-07-27 08:27:58

不幸的是,这取决于您的目的。
如果您打算将图像用于风格目的,那么最好的选择是使用精灵。
http://www.alistapart.com/articles/sprites2

但是,如果您打算使用 中的图像 标签,那么您需要预先加载它们

function preload(sources)
{
  var images = [];
  for (i = 0, length = sources.length; i < length; ++i) {
    images[i] = new Image();
    images[i].src = sources[i];
  }
}

(修改后的源代码取自 在 JavaScript 中预加载多个图像的最佳方法是什么?

使用 new Image() 不涉及使用 DOM 方法的费用,但对指定图像的新请求将添加到队列中。 由于此时图像并未实际添加到页面,因此不涉及重新渲染。 不过,我建议将其添加到页面末尾(如果可能的话,所有脚本都应该如此),以防止它占用更多关键元素。

编辑:编辑以非常正确地反映评论,指出需要单独的 Image 对象才能正常工作。 谢谢,我很抱歉没有更仔细地检查它。

Edit2:进行编辑以使可重用性更加明显

编辑3(3年后):

由于浏览器处理不可见图像的方式发生变化(显示:无,或者如本答案所示,从未附加到document)首选新的预加载方法。

您可以使用 Ajax 请求强制提前检索图像。 例如,使用 jQuery:

jQuery.get(source);

或者在我们前面的示例的上下文中,您可以执行以下操作:

function preload(sources)
{
  jQuery.each(sources, function(i,source) { jQuery.get(source); });
}

请注意,这不适用于按原样良好的精灵的情况。 这仅适用于照片库或带有图像的滑块/轮播等,其中图像未加载,因为它们最初不可见。

另请注意,此方法不适用于 IE(ajax 通常不用于检索图像数据)。

Unfortunately, that depends on your purpose.
If you plan to use the images for purposes of style, your best bet is to use sprites.
http://www.alistapart.com/articles/sprites2

However, if you plan to use the images in <img> tags, then you'll want to pre-load them with

function preload(sources)
{
  var images = [];
  for (i = 0, length = sources.length; i < length; ++i) {
    images[i] = new Image();
    images[i].src = sources[i];
  }
}

(modified source taken from What is the best way to preload multiple images in JavaScript?)

using new Image() does not involve the expense of using DOM methods but a new request for the image specified will be added to the queue. As the image is, at this point, not actually added to the page, there is no re-rendering involved. I would recommend, however, adding this to the end of your page (as all of your scripts should be, when possible) to prevent it from holding up more critical elements.

Edit: Edited to reflect comment quite correctly pointing out that separate Image objects are required to work properly. Thanks, and my bad for not checking it more closely.

Edit2: edited to make the reusability more obvious

Edit 3 (3 years later):

Due to changes in how browsers handle non-visible images (display:none or, as in this answer, never appended to the document) a new approach to pre-loading is preferred.

You can use an Ajax request to force early retrieval of images. Using jQuery, for example:

jQuery.get(source);

Or in the context of our previous example, you could do:

function preload(sources)
{
  jQuery.each(sources, function(i,source) { jQuery.get(source); });
}

Note that this doesn't apply to the case of sprites which are fine as-is. This is just for things like photo galleries or sliders/carousels with images where the images aren't loading because they are not visible initially.

Also note that this method does not work for IE (ajax is normally not used to retrieve image data).

反话 2024-07-27 08:27:58

Spriting

正如其他人所提到的,由于多种原因,Spriting 效果很好,但是,它并不像看起来那么好。

  • 好的一面是,您最终只需对图像发出一次 HTTP 请求。 不过,YMMV。
  • 缺点是您需要在一个 HTTP 请求中加载所有内容。 由于当前大多数浏览器仅限于 2 个并发连接,因此图像请求可能会阻止其他请求。 因此,YMMV 和菜单背景之类的东西可能会暂时无法渲染。
  • 多个图像共享相同的调色板,因此可以节省一些资源,但情况并非总是如此,即使如此,它也可以忽略不计。
  • 由于图像之间有更多的共享数据,因此压缩率得到了改善。

但处理不规则形状是很棘手的。 将所有新图像合并到新图像中是另一个烦恼。

使用 的低插孔方法 标签

如果您正在寻找最明确的解决方案,那么您应该采用我仍然喜欢的低杰克方法。 创建 链接到文档末尾的图像,并将宽度高度设置为1x1像素,然后将它们放入隐藏的div中。 如果它们位于页面末尾,则会在其他内容之后加载。

Spriting

As others have mentioned, spriting works quite well for a variety of reasons, however, it's not as good as its made out to be.

  • On the upside, you end up making only one HTTP request for your images. YMMV though.
  • On the down side you are loading everything in one HTTP request. Since most current browsers are limited to 2 concurrent connections the image request can block other requests. Hence YMMV and something like your menu background might not render for a bit.
  • Multiple images share the same color palette so there is some saving but this is not always the case and even so it's negligible.
  • Compression is improved because there is more shared data between images.

Dealing with irregular shapes is tricky though. Combining all new images into the new one is another annoyance.

Low jack approach using <img> tags

If you are looking for the most definitive solution then you should go with the low-jack approach which I still prefer. Create <img> links to the images at the end of your document and set the width and height to 1x1 pixel and additionally put them in a hidden div. If they are at the end of the page, they will be loaded after other content.

忆依然 2024-07-27 08:27:58

截至 2013 年 1 月,此处描述的方法均不适用于我,因此这里是在 Chrome 25 和 Firefox 18 上进行测试和使用的方法。使用 jQuery 和 此插件来解决加载事件怪癖:

function preload(sources, callback) {
    if(sources.length) {
        var preloaderDiv = $('<div style="display: none;"></div>').prependTo(document.body);

        $.each(sources, function(i,source) {
            $("<img/>").attr("src", source).appendTo(preloaderDiv);

            if(i == (sources.length-1)) {
                $(preloaderDiv).imagesLoaded(function() {
                    $(this).remove();
                    if(callback) callback();
                });
            }
        });
    } else {
        if(callback) callback();
    }
}

用法:

preload(['/img/a.png', '/img/b.png', '/img/c.png'], function() { 
    console.log("done"); 
});

请注意,如果禁用缓存,您将得到混合结果,当开发人员工具打开时,Chrome 上默认情况下是禁用缓存的,所以记住这一点。

As of January 2013 none of the methods described here worked for me, so here's what did instead, tested and working with Chrome 25 and Firefox 18. Uses jQuery and this plugin to work around the load event quirks:

function preload(sources, callback) {
    if(sources.length) {
        var preloaderDiv = $('<div style="display: none;"></div>').prependTo(document.body);

        $.each(sources, function(i,source) {
            $("<img/>").attr("src", source).appendTo(preloaderDiv);

            if(i == (sources.length-1)) {
                $(preloaderDiv).imagesLoaded(function() {
                    $(this).remove();
                    if(callback) callback();
                });
            }
        });
    } else {
        if(callback) callback();
    }
}

Usage:

preload(['/img/a.png', '/img/b.png', '/img/c.png'], function() { 
    console.log("done"); 
});

Note that you'll get mixed results if the cache is disabled, which it is by default on Chrome when the developer tools are open, so keep that in mind.

奶气 2024-07-27 08:27:58

在我看来,使用一些库引入的 Multipart XMLHttpRequest 将是未来几年的首选解决方案。 然而 IE < v8,仍然不支持data:uri(即使IE8也有有限的支持,最多允许32kb)。 以下是并行图像预加载的实现 - http://code.google.com/ p/core-framework/wiki/ImagePreloading ,它捆绑在框架中,但仍然值得一看。

In my opinion, using Multipart XMLHttpRequest introduced by some libraries will be a preferred solution in the following years. However IE < v8, still don't support data:uri (even IE8 has limited support, allowing up to 32kb). Here is an implementation of parallel image preloading - http://code.google.com/p/core-framework/wiki/ImagePreloading , it's bundled in framework but still worth taking a look.

花想c 2024-07-27 08:27:58

这是很久以前的事了,所以我不知道有多少人仍然对预加载图像感兴趣。

我的解决方案更加简单。

我刚刚使用了CSS。

#hidden_preload {
    height: 1px;
    left: -20000px;
    position: absolute;
    top: -20000px;
    width: 1px;
}

This was from a long time ago so I dont know how many people are still interested in preloading an image.

My solution was even more simple.

I just used CSS.

#hidden_preload {
    height: 1px;
    left: -20000px;
    position: absolute;
    top: -20000px;
    width: 1px;
}
不再见 2024-07-27 08:27:58

这是我的简单解决方案,在加载图像后淡入图像。

    function preloadImage(_imgUrl, _container){
        var image = new Image();
            image.src = _imgUrl;
            image.onload = function(){
                $(_container).fadeTo(500, 1);
            };
        }

Here goes my simple solution with a fade in on the image after it is loaded.

    function preloadImage(_imgUrl, _container){
        var image = new Image();
            image.src = _imgUrl;
            image.onload = function(){
                $(_container).fadeTo(500, 1);
            };
        }
人生百味 2024-07-27 08:27:58

对于我的用例,我有一个带有我想要预加载的全屏图像的轮播。 然而,由于图像按顺序显示,并且每个图像可能需要几秒钟的时间来加载,因此按顺序加载它们很重要。

为此,我使用了异步库的 waterfall() 方法 (https://github.com/async#waterfall")。 com/caolan/async#waterfall

        // Preload all images in the carousel in order.
        image_preload_array = [];
        $('div.carousel-image').each(function(){
            var url = $(this).data('image-url');
            image_preload_array.push(function(callback) {
                var $img = $('<img/>')
                $img.load(function() {
                    callback(null);
                })[0].src = url;
            });
        });
        async.waterfall(image_preload_array);

这通过创建一个函数数组来工作,每个函数都会传递参数callback(),它需要执行该参数才能调用下一个函数数组。 callback() 的第一个参数是错误消息,如果提供非 null 值,则会退出序列,因此我们每次都传递 null。

For my use case I had a carousel with full screen images that I wanted to preload. However since the images display in order, and could take a few seconds each to load, it's important that I load them in order, sequentially.

For this I used the async library's waterfall() method (https://github.com/caolan/async#waterfall)

        // Preload all images in the carousel in order.
        image_preload_array = [];
        $('div.carousel-image').each(function(){
            var url = $(this).data('image-url');
            image_preload_array.push(function(callback) {
                var $img = $('<img/>')
                $img.load(function() {
                    callback(null);
                })[0].src = url;
            });
        });
        async.waterfall(image_preload_array);

This works by creating an array of functions, each function is passed the parameter callback() which it needs to execute in order to call the next function in the array. The first parameter of callback() is an error message, which will exit the sequence if a non-null value is provided, so we pass null each time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文