资讯专栏INFORMATION COLUMN

Javascript实现图片的预加载功能

KavenFan / 1350人阅读

摘要:本文同步自我得博客最近要用做一个动画功能,为了确保动画在播放的时候能够顺利和平滑,我需要对所用到的图片素材进行预加载,下面跟大家分享一下我实现这个功能的过程单图片预加载目前最常见的一种实现方式如下接下来可以使用图片了接下来可以使用图片了首先

本文同步自我得博客: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个不能忍受的问题

首先,我很有可能拿不到最后返回的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数组的数据时就能够顺利获取到
在这次的代码中,我们引入了jQueryDeferred对象,这样更方便我把握整个预加载图片的过程,Deferred对象或者Promise对象的实现原理可以参看我的这篇文章

thx for reading, hope u enjoy

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85310.html

相关文章

  • 图片的预加载和懒加载

    摘要:图片的预加载是提升用户体验而损失性能的一种做法,而懒加载的性能就比较好了,所以将两个结合起来放到程序中是一种不错的选择。 最近在做H5滑页时,遇到一些比较大的场景,动辄二十、三十页,而图片更是可恨的能达到上百个,所以就会导致场景在加载的时候遇到网速比较慢的时候,用户等待的时间特别长,这样的话,就有可能导致一部分的用户没有耐心,而丢失这部分用户,于是就有了这里的图片的预加载和懒加载,记个...

    SwordFly 评论0 收藏0
  • Link 标签的预加载机制

    摘要:但这些加载器对于浏览器的加载优先级队列完全束手无策,这也使得他们不得不屈服于同样的性能问题。 参考文章:https://developer.mozilla.org... 先简单介绍下 link 标签作用 你可以在页面 元素内部使用 标签书写一些声明式的资源获取请求 preload (预加载) 有些资源是在页面加载完成后即刻需要的,对于这种即刻需要的资源,你可能希望在页面加载的生命...

    付永刚 评论0 收藏0
  • 前端笔记(二) 对象的深浅拷贝,函数的防抖与节流,函数柯里化 ,图片的预加载与懒加载

    摘要:对象是无法通过这种方式深拷贝。这就是函数防抖和节流要做的事情。函数防抖当触发频率过高时函数基本停止执行而函数节流则是按照一定的频率执行事件。 对象的深浅拷贝 对象的深拷贝与浅拷贝的区别: 浅拷贝:仅仅复制对象的引用, 而不是对象本身。 深拷贝:把复制的对象所引用的全部对象都复制一遍 浅拷贝的实现: var obj = { age : 18, person : { ...

    dongxiawu 评论0 收藏0
  • javascript 代理模式

    摘要:虚拟代理在开发中,我们往往将这个对象的实例化操作,放到函数内部执行,这样的操作会减少不必要的实例化对象的开销,造成资源的浪费。这种使用的情况我们将之成为虚拟代理。但是在中我们使用最多,也最常见的就是虚拟代理和缓存代理。 所谓的的代理模式就是为一个对象找一个替代对象,以便对原对象进行访问。 使用代理的原因是我们不愿意或者不想对原对象进行直接操作,我们使用代理就是让它帮原对象进行一系列的操...

    张利勇 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<