使用JavaScript / jQuery预加载图像的权威最佳方式?

时间:2022-10-12 21:49:58

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.

我完全清楚这个问题已经在所有地方得到了回答,无论是在SO还是关闭。但是,每次似乎有不同的答案,例如这个,这个和那个。

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

我不关心它是否使用jQuery - 重要的是它是有效的,并且是跨浏览器。

So, what is the best way to preload images?

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

8 个解决方案

#1


64  

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

不幸的是,这取决于你的目的。如果您打算将图像用于样式,最好的办法是使用精灵。 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

但是,如果您打算使用使用JavaScript / jQuery预加载图像的权威最佳方式?标签中的图像,那么您需要预先加载它们

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?)

(修改后的源代码来源于在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.

使用新的Image()不涉及使用DOM方法的费用,但是对指定图像的新请求将被添加到队列中。由于图像在此时未实际添加到页面中,因此不会涉及重新呈现。但是,我建议将其添加到页面的末尾(因为所有脚本应尽可能),以防止它占用更多关键元素。

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

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

Edit 3 (3 years later):

编辑3(3年后):

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:

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

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).

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

#2


13  

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.
  • 从好的方面来说,您最终只能为图像发出一个HTTP请求。但YMMV。
  • 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.
  • 在不利方面,您将在一个HTTP请求中加载所有内容。由于大多数当前浏览器限于2个并发连接,因此图像请求可以阻止其他请求。因此,YMMV和菜单背景之类的东西可能不会渲染一点。
  • 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

使用使用JavaScript / jQuery预加载图像的权威最佳方式?标签的低插孔方法

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.

如果您正在寻找最明确的解决方案,那么您应该采用我更喜欢的低插孔方法。创建使用JavaScript / jQuery预加载图像的权威最佳方式?链接到文档末尾的图像,并将宽度和高度设置为1x1像素,并另外将它们放在隐藏的div中。如果它们位于页面的末尾,则会在其他内容之后加载它们。

#3


6  

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:

截至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();
    }
}

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.

请注意,如果禁用缓存,您将获得混合结果,默认情况下,当开发人员工具处于打开状态时,Chrome会默认显示,因此请记住这一点。

#4


3  

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.

在我看来,使用一些库引入的Multipart XMLHttpRequest将是接下来几年的首选解决方案。但是IE ,仍然不支持数据:uri(即使ie8支持有限,允许最多32kb)。这是一个并行图像预加载的实现>

#5


1  

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.

我只是用CSS。

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

#6


0  

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);
            };
        }

#7


0  

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)

为此,我使用了异步库的waterfall()方法(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.

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

#8


-2  

See this:

看到这个:

http://www.mattfarina.com/2007/02/01/preloading_images_with_jquery

http://www.mattfarina.com/2007/02/01/preloading_images_with_jquery

Related question on SO:

关于SO的相关问题:

jquery hidden preload

jquery隐藏预加载

#1


64  

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

不幸的是,这取决于你的目的。如果您打算将图像用于样式,最好的办法是使用精灵。 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

但是,如果您打算使用使用JavaScript / jQuery预加载图像的权威最佳方式?标签中的图像,那么您需要预先加载它们

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?)

(修改后的源代码来源于在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.

使用新的Image()不涉及使用DOM方法的费用,但是对指定图像的新请求将被添加到队列中。由于图像在此时未实际添加到页面中,因此不会涉及重新呈现。但是,我建议将其添加到页面的末尾(因为所有脚本应尽可能),以防止它占用更多关键元素。

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

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

Edit 3 (3 years later):

编辑3(3年后):

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:

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

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).

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

#2


13  

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.
  • 从好的方面来说,您最终只能为图像发出一个HTTP请求。但YMMV。
  • 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.
  • 在不利方面,您将在一个HTTP请求中加载所有内容。由于大多数当前浏览器限于2个并发连接,因此图像请求可以阻止其他请求。因此,YMMV和菜单背景之类的东西可能不会渲染一点。
  • 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

使用使用JavaScript / jQuery预加载图像的权威最佳方式?标签的低插孔方法

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.

如果您正在寻找最明确的解决方案,那么您应该采用我更喜欢的低插孔方法。创建使用JavaScript / jQuery预加载图像的权威最佳方式?链接到文档末尾的图像,并将宽度和高度设置为1x1像素,并另外将它们放在隐藏的div中。如果它们位于页面的末尾,则会在其他内容之后加载它们。

#3


6  

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:

截至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();
    }
}

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.

请注意,如果禁用缓存,您将获得混合结果,默认情况下,当开发人员工具处于打开状态时,Chrome会默认显示,因此请记住这一点。

#4


3  

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.

在我看来,使用一些库引入的Multipart XMLHttpRequest将是接下来几年的首选解决方案。但是IE ,仍然不支持数据:uri(即使ie8支持有限,允许最多32kb)。这是一个并行图像预加载的实现>

#5


1  

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.

我只是用CSS。

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

#6


0  

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);
            };
        }

#7


0  

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)

为此,我使用了异步库的waterfall()方法(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.

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

#8


-2  

See this:

看到这个:

http://www.mattfarina.com/2007/02/01/preloading_images_with_jquery

http://www.mattfarina.com/2007/02/01/preloading_images_with_jquery

Related question on SO:

关于SO的相关问题:

jquery hidden preload

jquery隐藏预加载