Javascript完成图片的预加载功用

本文同步自我得博客: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指定的图片地点,接着推断imgcomplete属性,假如当地有这张图片的缓存,则该值为true,此时我们能够直接操纵这张图片,假如当地没有缓存,则该值为false,此时我们须要监听imgonload事宜,把对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个不能忍耐的题目

  1. 起首,我很有能够拿不到末了返回的imgs数组,由于只需有图片在当地没有缓存,imgs的存储操纵都邑放到onload的回调事宜中,而事宜监听也属于javascript中异步操纵的一种,在绑定完onload事宜的回调函数后,preloadImg函数就实行完毕了,没有任何返回值,外部imgs变量接收到的值为undefined,只要在一切图片都有当地缓存的情况下,外部imgs变量才顺遂拿到存储了悉数预加载图片资本的数组

  2. 在加载完一张图片以后才去加载下一张,全部预加载图片的历程所须要的时候相对会比较长,用户体验会下降,而且原本异步操纵详细速度快的特征,如许的完成体式格局即是完整弃置了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数组的数据时就能够顺遂获取到
在此次的代码中,我们引入了jQueryDeferred对象,如许更轻易我把握全部预加载图片的历程,Deferred对象或许Promise对象的完成道理能够参看我的这篇文章

thx for reading, hope u enjoy

    原文作者:JoeRay61
    原文地址: https://segmentfault.com/a/1190000000684923
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞