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

时间:2009-05-23 15:02:17

标签: javascript jquery image-preloader

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

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

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

8 个答案:

答案 0 :(得分:65)

不幸的是,这取决于你的目的。 如果您打算将图像用于样式,最好的办法是使用精灵。 http://www.alistapart.com/articles/sprites2

但是,如果您打算使用< img>中的图片标签,然后你会想要用

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

(修改后的来源于What is the best way to preload multiple images in JavaScript?

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

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

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

编辑3(3年后):

由于浏览器处理不可见图像的方式发生了变化(显示:无,或者在本答复中,从未附加到文档中),因此首选新的预加载方法。

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

jQuery.get(source);

或者在上一个示例的上下文中,您可以这样做:

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

请注意,这不适用于精细的精灵情况。这仅适用于照片画廊或滑块/旋转木马等带图像的图像未加载的图像,因为它们最初不可见。

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

答案 1 :(得分:14)

<强>拼合

正如其他人所说的那样,出于各种原因,精灵作品效果很好,但是它并不像它的那样好。

  • 从好的方面来说,您最终只会为图片发出一个HTTP请求。 YMMV虽然。
  • 在下方,您将在一个HTTP请求中加载所有内容。由于大多数当前浏览器限于2个并发连接,因此图像请求可以阻止其他请求。因此,YMMV和菜单背景之类的东西可能不会呈现一点。
  • 多个图像共享相同的调色板,因此有一些保存,但情况并非总是如此,即使如此也可以忽略不计。
  • 压缩得到改善,因为图像之间存在更多共享数据。

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

使用&lt; img&gt;的低插孔方法代码

如果您正在寻找最明确的解决方案,那么您应该采用我更喜欢的低插孔方法。创建&lt; img&gt;链接到文档末尾的图像,并将widthheight设置为1x1像素,并将它们另外放入隐藏的div中。如果它们位于页面的末尾,则会在其他内容之后加载它们。

答案 2 :(得分:6)

截至2013年1月,这里描述的方法都没有为我工作,所以这里是做了什么,测试和使用Chrome 25和Firefox 18.使用jQuery和this plugin来解决加载事件的怪癖:< / p>

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会默认显示,因此请记住这一点。

答案 3 :(得分:3)

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

答案 4 :(得分:1)

这是很久以前的事情,所以我不知道还有多少人对预装图像感兴趣。

我的解决方案更简单。

我刚刚使用CSS。

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

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

对于我的用例,我有一个带有全屏图像的旋转木马,我想要预装。然而,由于图像按顺序显示,并且每个图像可能需要几秒钟才能加载,因此按顺序加载它们非常重要。

为此,我使用了异步库的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);

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

答案 7 :(得分:-2)