本文同步自我得博客:http://www.joeray61.com
近来要用javascript
做一个动画功用,为了确保动画在播放的时刻能够顺遂和腻滑,我须要对所用到的图片素材举行预加载,下面跟人人分享一下我完成这个功用的历程
单图片预加载
现在最常见的一种完成体式格局以下
function preloadImg(url) {
var img = new Image();
img.src = url;
if(img.complete) {
//接下来能够运用图片了
//do something here
}
else {
img.onload = function() {
//接下来能够运用图片了
//do something here
};
}
}
起首实例化一个Image
对象赋值给img
,然后设置img.src
为参数url
指定的图片地点,接着推断img
的complete
属性,假如当地有这张图片的缓存,则该值为true
,此时我们能够直接操纵这张图片,假如当地没有缓存,则该值为false
,此时我们须要监听img
的onload
事宜,把对img
的操纵放在onload
的回调函数内里,经由测试,这类计划基本能够兼容现在一切浏览器
多图片预加载
许多场景下,单图片预加载并不能满足我们的需求,由于像动画这类功用一般都邑有许多的图片素材,接下来我们就在原本单图片预加载的基本上来革新我们的函数
function preloadImg(list) {
var imgs = arguments[1] || [], //用于存储预加载好的图片资本
fn = arguments.cal lee;
if(list.length == 0) {
return imgs;
}
var img = new Image();
img.src = list[0];
if(img.complete) {
imgs.push(img);
list.shift();
fn(list, imgs);
}
else {
img.onload = function() {
imgs.push(img);
list.shift();
fn(list, imgs);
};
}
}
var list = [......], //此处省略一万个字符
imgs = preloadImg();
由于帧动画能够须要保证每一帧动画所用的图片的递次,所以我在这段代码中运用递归的体式格局,在上一张加载完成以后再去加载下一张图片,每加载一张图片,就把这张图片资本存储到imgs
数组中,而且把这张图片的地点从地点数组list
中去掉,当list
中已没有地点的时刻跳出递归,并返回imgs
数组
想象很优美,实际很严酷,这段代码有2个不能忍耐的题目
起首,我很有能够拿不到末了返回的
imgs
数组,由于只需有图片在当地没有缓存,imgs
的存储操纵都邑放到onload
的回调事宜中,而事宜监听也属于javascript
中异步操纵的一种,在绑定完onload
事宜的回调函数后,preloadImg
函数就实行完毕了,没有任何返回值,外部imgs
变量接收到的值为undefined
,只要在一切图片都有当地缓存的情况下,外部imgs
变量才顺遂拿到存储了悉数预加载图片资本的数组在加载完一张图片以后才去加载下一张,全部预加载图片的历程所须要的时候相对会比较长,用户体验会下降,而且原本异步操纵详细速度快的特征,如许的完成体式格局即是完整弃置了
onload
异步的这个特征
多图片预加载(革新版)
此次我们直接把一个空数组作为参数传进函数,图片悉数存储到这个数组内里,下面是革新后的函数代码(假定我们能够运用jQuery
)
function preloadImg(list,imgs) {
var def = $.Deferred(),
len = list.length;
$(list).each(function(i,e) {
var img = new Image();
img.src = e;
if(img.complete) {
imgs[i] = img;
len--;
if(len == 0) {
def.resolve();
}
}
else {
img.onload = (function(j) {
return function() {
imgs[j] = img
len--;
if(len == 0) {
def.resolve();
}
};
})(i);
img.onerror = function() {
len--;
console.log('fail to load image');
};
}
});
return def.promise();
}
var list = [......], //此处省略一万个字符
imgs = [];
$.when(preloadImg(list, imgs)).done(
function() {
//预加载完毕
//do something here
}
);
在分别给每个img
绑定onload
的回调函数时采用了闭包的体式格局,目标是为了保留住当前的递增变量i
,如果不这么做,效果将会是list
地点中没有当地缓存的图片都存储到imgs
的末了一个元素上
此次每载入一张图片,我们并没有把这张图片的地点从list
数组中去掉,如许后续须要运用list
数组的数据时就能够顺遂获取到
在此次的代码中,我们引入了jQuery
的Deferred
对象,如许更轻易我把握全部预加载图片的历程,Deferred
对象或许Promise
对象的完成道理能够参看我的这篇文章
thx for reading, hope u enjoy