js图片预加载技术解析

lightbox类效果为了让图片居中显示而使用预加载,需要等待完全加载完毕才能显示,体验不佳(如filick相册的全屏效果)。javascript无法获取img文件头数据,真的是这样吗?本文通过一个巧妙的方法让javascript获取它。

这是大部分人使用预加载获取图片大小的例子:

  1. var imgLoad=function(url,callback){ 
  2.     var img=new Image(); 
  3.     img.src=url; 
  4.     if(img.complete){ 
  5.         callback(img.width,img.height); 
  6.     } else
  7.         img.onload=function(){ 
  8.             callback(img.width,img.height); 
  9.             img.onload=null
  10.         }; 
  11.     }; 
  12. }; 

可以看到上面必须等待图片加载完毕才能获取尺寸,其速度不敢恭维,我们需要改进。

web应用程序区别于桌面应用程序,响应速度才是最好的用户体验。如果想要速度与优雅兼得,那就必须提前获得图片尺寸,如何在图片没有加载完毕就能获取图片尺寸?

十多年的上网经验告诉我:浏览器在加载图片的时候你会看到图片会先占用一块地然后才慢慢加载完毕,并且不需要预设width与height属性,因为浏览器能够获取图片的头部数据。基于此,只需要使用javascript定时侦测图片的尺寸状态便可得知图片尺寸就绪的状态。

当然实际中会有一些兼容陷阱,如width与height检测各个浏览器的不一致,还有webkit new Image()建立的图片会受以处在加载进程中同url图片影响,经过反复测试后的最佳处理方式:

  1. // 更新: 
  2. // 05.27:1、保证回调执行顺序:error > ready > load;2、回调函数this指向img本身 
  3. // 04-02:1、增加图片完全加载后的回调 2、提高性能 
  4. /** 
  5.  * 图片头数据加载就绪事件 - 更快获取图片尺寸 
  6.  * @version 2011.05.27 
  7.  * @author  TangBin 
  8.  * @param   {String}    图片路径 
  9.  * @param   {Function}  尺寸就绪 
  10.  * @param   {Function}  加载完毕(可选) 
  11.  * @param   {Function}  加载错误(可选) 
  12.  */ 
  13. var imgReady=(function(){ 
  14.     var list=[],intervalId=null
  15.     // 用来执行队列 
  16.     tick=function(){ 
  17.         var i=0; 
  18.         for(;i<list.length;i++){ 
  19.             list[i].end?list.splice(i--,1):list[i](); 
  20.         }; 
  21.         !list.length&&stop(); 
  22.     }, 
  23.     // 停止所有定时器队列 
  24.     stop=function(){ 
  25.         clearInterval(intervalId); 
  26.         intervalId=null
  27.     }; 
  28.     return function(url,ready,load,error){ 
  29.         var onready,width,height,newWidth,newHeight, 
  30.         img=new Image(); 
  31.         img.src=url; 
  32.         // 如果图片被缓存,则直接返回缓存数据 
  33.         if(img.complete){ 
  34.             ready.call(img); 
  35.             load&&load.call(img); 
  36.             return
  37.         }; 
  38.         width=img.width; 
  39.         height=img.height; 
  40.         // 加载错误后的事件 
  41.         img.onerror=function(){ 
  42.             error&&error.call(img); 
  43.             onready.end=true
  44.             img=img.onload=img.onerror=null
  45.         }; 
  46.         // 图片尺寸就绪 
  47.         onready=function(){ 
  48.             newWidth=img.width; 
  49.             newHeight=img.height; 
  50.             if(newWidth !== width || newHeight !== height || 
  51.                 // 如果图片已经在其他地方加载可使用面积检测 
  52.                 newWidth * newHeight > 1024 
  53.             ){ 
  54.                 ready.call(img); 
  55.                 onready.end=true
  56.             }; 
  57.         }; 
  58.         onready(); 
  59.         // 完全加载完毕的事件 
  60.         img.onload=function(){ 
  61.             // onload在定时器时间差范围内可能比onready快 
  62.             // 这里进行检查并保证onready优先执行 
  63.             !onready.end&&onready(); 
  64.             load&&load.call(img); 
  65.             // IE gif动画会循环执行onload,置空onload即可 
  66.             img=img.onload=img.onerror=null
  67.         }; 
  68.         // 加入队列中定期执行 
  69.         if(!onready.end){ 
  70.             list.push(onready); 
  71.             // 无论何时只允许出现一个定时器,减少浏览器性能损耗 
  72.             if(intervalId === null) intervalId=setInterval(tick,40); 
  73.         }; 
  74.     }; 
  75. })(); 

调用例子如下:

  1. imgReady('http://www.daimajiayuan.com/uploads/1305/iwzzw.com.jpg',function(){ 
  2.     alert('size ready:width='+this.width+';height='+this.height); 
  3. }); 

是不是很简单?这样的方式获取摄影级别照片尺寸的速度往往是onload方式的几十多倍,而对于web普通(800×600内)浏览级别的图片能达到秒杀效果。看了这个再回忆一下你见过的web相册,是否绝大部分都可以重构一下呢?

下面列出本站内更多的图片预加载文章或软件:

jQuery图片延迟加载插件

图片预加载、自动等比缩放jQuery插件

jQuery预加载插件 jQuery-preloader

Lazyload图片延迟加载效果

转载请注明:代码家园 » js图片预加载技术解析

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)