使用JavaScript / jQuery预加载图像的最佳方法是什么?
我完全意识到,这个问题已经被问及到处都回答了,无论是在SO还是在OFF。 然而,每一次似乎有不同的答案,例如这个 , 这个和那个 。
我不在乎它是否使用jQuery – 重要的是它的工作原理,并且是跨浏览器。
那么,预加载图像的最佳方法是什么?
不幸的是,这取决于你的目的。 如果你打算使用风格的图像,最好的select是使用精灵。 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]; } }
(修改的源代码是什么是预加载多个图像在JavaScript中的最佳方式? )
使用new Image()
不涉及使用DOM方法的开销,但是指定图像的新请求将被添加到队列中。 由于图像在这一点上并未实际添加到页面中,因此不涉及重新渲染。 但是,我build议将其添加到页面的最后(因为所有的脚本都应该尽可能),以防止它阻塞更多的关键元素。
编辑:编辑反映评论相当正确指出,单独的Image
对象需要正常工作。 谢谢,我的不好,不仔细检查。
编辑2:编辑使重复使用更加明显
编辑3(3年后):
由于浏览器处理不可见图像的方式发生了变化(显示:无,或者如在此答案中,从未附加到文档中),所以预加载的新方法是优选的。
您可以使用Ajax请求强制早期检索图像。 使用jQuery,例如:
jQuery.get(source);
或者在我们之前的例子中,你可以这样做:
function preload(sources) { jQuery.each(sources, function(i,source) { jQuery.get(source); }); }
请注意,这并不适用于原样好的精灵。 这只是像照片画廊或滑块/旋转木马与图像不加载,因为它们是最初不可见的图像。
另外请注意,这种方法不适用于IE(ajax通常不用于检索图像数据)。
拼合
正如其他人所说的那样,由于种种原因,spriting运行得非常好,但是它并不像它那样好。
- 另一方面,你最终只能为你的图像做一个HTTP请求。 YMMV虽然。
- 在不利的方面,你正在加载一个HTTP请求的一切。 由于大多数当前浏览器被限制为2个并发连接,所以图像请求可以阻止其他请求。 因此,YMMV和你的菜单背景可能不会呈现一点点。
- 多个图像共享相同的调色板,所以有一些节省,但这并不总是如此,即使如此,它是微不足道的。
- 由于图像之间有更多的共享数据,所以压缩得到了改善。
处理不规则的形状是棘手的。 将所有新的图像合并成新的图像是另一个烦恼。
使用<img>标签的低插孔方法
如果你正在寻找最权威的解决scheme,那么你应该采用我更喜欢的低插口方法。 在文档的末尾创build<img>指向图像的链接,并将width
和height
设置为1×1像素,并将其放置在隐藏的div中。 如果他们在页面的最后,他们将被加载其他内容之后。
截至2013年1月,这里描述的方法都没有为我工作,所以这里是什么,而是testing和使用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"); });
请注意,如果禁用了caching,那么在开发人员工具处于打开状态时,默认情况下会在Chrome上得到混合结果,因此请记住这一点。
在我看来,使用某些库引入的Multipart XMLHttpRequest将成为未来几年的首选解决scheme。 不过IE <v8,依然不支持数据:uri(即使IE8支持有限,最高可达32kb)。 这是一个并行图像预加载的实现 – http://code.google.com/p/core-framework/wiki/ImagePreloading ,它是捆绑在框架中,但仍值得一看。
这是很久以前,所以我不知道有多less人仍然有兴趣预载图像。
我的解决scheme更加简单。
我只是使用CSS。
#hidden_preload { height: 1px; left: -20000px; position: absolute; top: -20000px; width: 1px; }
这里是我的简单的解决scheme,加载后的图像淡入淡出。
function preloadImage(_imgUrl, _container){ var image = new Image(); image.src = _imgUrl; image.onload = function(){ $(_container).fadeTo(500, 1); }; }
对于我的使用案例,我有一个全屏图像的旋转木马,我想预先加载。 但是,由于图像按顺序显示,并且可能需要几秒钟才能加载,因此按顺序加载它们非常重要。
为此我使用了asynchronous库的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);
这是通过创build一个函数数组,每个函数传递参数callback()
,它需要执行以调用数组中的下一个函数。 callback()
的第一个参数是一个错误消息,如果提供了一个非空的值,它将退出序列,所以我们每次都传递null。