图片预加载

今天在做页面的时候需要实现图片预加载的功能,保证迅速正常的显示。

解决方式:

css方式,将图片作为背景图片加载

.pic{background-image: url(image/demo.png) no-repeat -9999px -9999px;}

这种方式的前提是,进入页面后的图片不会立即用到。如果一打开页面就需要看到完整图片,这种方式也还是挺耗时间的。

通过javascript加载图片:

首先创建一个Image对象,实现图片的预加载;然后检测图片是否存在缓存中如果存在就直接调用回调函数,若不在执行 onload() 方法。

function preLoadImages(url,callback){
    var img = new Image();  
    img.src = url;
    if(img.complate){   //判断图片是否在缓存中
        callback(img);
        return;
    }
    img.onload = function(){    //下载图片异步调用callback函数
        callback(img);
    }
}

分析:这个方式还是有一些问题
1.创建了一个临时的匿名函数来作为图片的onload事件处理函数,形成了闭包。闭包有保存外部运行环境的能力(依赖于作用域链的实现),所以imag.onload这个函数内部有保存了对img的引用,这样就形成了循环作用,导致内存泄露。(这种方式只存在于与ie6,高版本的浏览器一般都不会出现内存泄露)。
2.只考虑了静态图片的加载,忽略了gif等动态图片,这些动态图片可能多次触发onload事件。
解决方式:

img.onload = function(){
    img.onload = null;
    callback(img);
}

关于这段代码,看相关博文里的叙述,原因如下:
经过对多个浏览器版本的测试,发现ie、opera下,当图片加载过一次以后,如果再有对该图片的请求时,由于浏览器已经缓存住这张图片了,不会再发起一次新的请求,而是直接从缓存中加载过来。对于 firefox和safari,它们试图使这两种加载方式对用户透明,同样会引起图片的onload事件,而ie和opera则忽略了这种同一性,不会引起图片的onload事件,因此上边的代码在它们里边不能得以实现效果。
确实,在ie,opera下,对于缓存图片的初始状态,与firefox和safari,chrome下是不一样的(有兴趣的话,可以在不同浏览器下,测试一下在给img的src赋值缓存图片的url之前,img的状态),但是对onload事件的触发,却是一致的,不管是什么浏览器。产生这个问题的根本原因在于,img的src赋值与 onload事件的绑定,顺序不对(在ie和opera下,先赋值src,再赋值onload,因为是缓存图片,就错过了onload事件的触发)。应该先绑定onload事件,然后再给src赋值,代码如下:

function loadImage(url, callback) {     
    var img = new Image(); //创建一个Image对象,实现图片的预下载     
    img.onload = function(){
        img.onload = null;
        callback(img);
    }
    img.src = url; 
}

这样内存泄漏,动态图片的加载问题都得到了解决,而且也以统一的方式,实现了callback的调用。

所以我使用了下面的代码:

function loadImage(url, callback) {     
    var img = new Image(); //创建一个Image对象,实现图片的预下载     
    img.onload = function(){
        img.onload = null;
        callback(img);
    }
    img.src = url; 
}

或者直接采用加载多张图的方法
1.

function preloadimages(arr, callback){
    var newimages=[], loadedimages=0
    var arr=(typeof arr!="object")? [arr] : arr
    function imageloadpost(){
        loadedimages++
        if (loadedimages==arr.length){
            //alert("图片已经加载完成")
            callback(newimages);
            return;
        }
    }
    for (var i=0; i<arr.length; i++){
        newimages[i]=new Image()
        newimages[i].src=arr[i]
        newimages[i].onload=function(){
            imageloadpost()
        }
        newimages[i].onerror=function(){
        imageloadpost()
        }
    }
}   
使用方法:
preloadimages(['1.gif', '2.gif', '3.gif'], function(images){
   //代码块
   console.log(images.length);
});
function preloadimages(arr){   
    var newimages=[], loadedimages=0
    var postaction=function(){}  //此处增加了一个postaction函数
    var arr=(typeof arr!="object")? [arr] : arr
    function imageloadpost(){
        loadedimages++
        if (loadedimages==arr.length){
            postaction(newimages) //加载完成用我们调用postaction函数并将newimages数组做为参数传递进去
        }
    }
    for (var i = 0; i<arr.length; i++){
        newimages[i] = new Image()
        newimages[i].src = arr[i]
        newimages[i].onload = function(){
            imageloadpost()
        }
        newimages[i].onerror = function(){
            imageloadpost()
        }
    }
    return { //此处返回一个空白对象的done方法
        done:function(f){
            postaction=f || postaction
        }
    }
}
使用方式:
 preloadimages(['1.gif', '2.gif', '3.gif']).done(function(images){
   alert(images.length) //alerts 3
   alert(images[0].src+" "+images[0].width) //alerts '1.gif 220'
})

代码地址
最后收藏一个 css3.0 实现的 load样式

posted @ 2015-11-19 00:16  coding不止步  阅读(272)  评论(0编辑  收藏  举报