再谈javascript图片预加载技术(详细演示)

  而本文所提到的预加载技术主要是让javascript快速获取图片头部数据的尺寸。

  一段典型的使用预加载获取图片大小的例子:

  

复制代码 代码如下:

  var imgLoad = function (url, callback) {

  var img = new Image();

  img.src = url;

  if (img.complete) {

  callback(img.width, img.height);

  } else {

  img.onload = function () {

  callback(img.width, img.height);

  img.onload = null;

  };

  };

  };

  可以看到使用onload的方式必须等待图片加载完毕,其速度不敢恭维。

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

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

  实现代码(2011-03-11更新):

  2011-03-12 更新:

  只使用一定时器,优化性能

  

复制代码 代码如下:

  /*!

  * img ready v0.3

  * http://www.planeart.cn/?p=1121

  * TangBin - MIT Licensed

  */

  // 图片头数据加载就绪事件

  // @param {String} 图片路径

  // @param {Function} 获取尺寸的回调函数 (参数1接收width;参数2接收height)

  // @param {Function} 加载错误的回调函数 (可选)

  (function () {

  var list = [], intervalId = null,

  tick = function () {

  var i = 0;

  for (; i < list.length; i++) {

  list[i].end ? list.splice(i--, 1) : list[i]();

  };

  !list.length && stop();

  },

  stop = function () {

  clearInterval(intervalId);

  intervalId = null;

  };

  this.imgReady = function (url, callback, error) {

  var check, end, width, height, offsetWidth, offsetHeight, div,

  accuracy = 1024,

  doc = document,

  container = doc.body || doc.getElementsByTagName('head')[0],

  img = new Image();

  img.src = url;

  if (!callback) return img;

  // 如果图片被缓存,则直接返回缓存数据

  if (img.complete) return callback(img.width, img.height);

  // 向页面插入隐秘图像,用来监听图片是否占位

  div = doc.createElement('div');

  div.style.cssText = 'visibility:hidden;position:absolute;left:0;top:0;width:1px;height:1px;overflow:hidden';

  div.appendChild(img)

  container.appendChild(div);

  width = img.offsetWidth;

  height = img.offsetHeight;

  // 完全加载完毕的事件

  img.onload = function () {

  end();

  callback(img.width, img.height);

  };

  // 加载错误后的事件

  img.onerror = function () {

  end();

  error && error();

  };

  // 检测图片是否已经占位

  check = function () {

  offsetWidth = img.offsetWidth;

  offsetHeight = img.offsetHeight;

  if (offsetWidth !== width || offsetHeight !== height || offsetWidth * offsetHeight > accuracy) {

  end();

  callback(offsetWidth, offsetHeight);

  };

  };

  check.url = url;

  // 操作结束后进行清理

  // 删除元素与事件,避免IE内存泄漏

  end = function () {

  check.end = true;

  img.onload = img.onerror = null;

  div.innerHTML = '';

  div.parentNode.removeChild(div);

  };

  // 将检测图片是否占位的函数加入定时器列队定期执行

  // 同一图片只加入一个检测器

  // 无论何时只允许出现一个定时器,减少浏览器性能损耗

  !check.end && check();

  for (var i = 0; i < list.length; i ++) {

  if (list[i].url === url) return;

  };

  if (!check.end) {

  list.push(check);

  if (!intervalId) intervalId = setInterval(tick, 150);

  };

  };

  })();

  是不是很简单?这样的方式获取摄影级别照片尺寸的速度往往是onload方式的几十多倍,而对于web普通(800×600内)浏览级别的图片能达到秒杀效果。

  好了,请观赏令人愉悦的 DEMO : http://demo.glzy8.com/js/2011/imgready/

  (通过测试的浏览器:Chrome、Firefox、Safari、Opera、IE6、IE7、IE8)

  来自:: 唐斌