欢迎光临

木子屋

标题: 关于图片的预加载,你所不知道的

作者: dnawo

日期: 2011-04-17 10:01 AM

分类: 脚本语言

内容: 看完了曼联与曼城的同城德比，还有漫长的两个小时，才能看到期待中的国家德比。无聊的很，左右无事，便来论坛闲逛。看到了一章关于图片预加载的博文，其代码如下：
复制内容到剪贴板 程序代码function loadImage(url, callback) {
var img = new Image(); //创建一个Image对象，实现图片的预下载
img.src = url;

if (img.complete) { // 如果图片已经存在于浏览器缓存，直接调用回调函数
callback(img);
return; // 直接返回，不用再处理onload事件
}

img.onload = function () { //图片下载完毕时异步调用callback函数。
callback(img);
};
}
在网上搜索了一下相关文章，大体上都是这个思路。
这个方法功能是ok的，但是有一些隐患。
1 创建了一个临时匿名函数来作为图片的onload事件处理函数，形成了闭包。
相信大家都看到过ie下的内存泄漏模式的文章，其中有一个模式就是循环引用，而闭包就有保存外部运行环境的能力（依赖于作用域链的实现），所以img.onload这个函数内部又保存了对img的引用，这样就形成了循环引用，导致内存泄漏。（这种模式的内存泄漏只存在低版本的ie6中，打过补丁的ie6以及高版本的ie都解决了循环引用导致的内存泄漏问题）。
2 只考虑了静态图片的加载，忽略了gif等动态图片，这些动态图片可能会多次触发onload。
要解决上面两个问题很简单，其实很简单，代码如下：
复制内容到剪贴板 程序代码img.onload = function () { //图片下载完毕时异步调用callback函数。
img.onload = null;
callback(img);
}
这样既能解决内存泄漏的问题，又能避免动态图片的事件多次触发问题。
在一些相关博文中，也有人注意到了要把img.onload 设置为null，只不过时机不对，大部分文章都是在callback运行以后，才将img.onload设置为null，这样虽然能解决循环引用的问题，但是对于动态图片来说，如果callback运行比较耗时的话，还是有多次触发的隐患的。
隐患经过上面的修改后，就消除了，但是这个代码还有优化的余地：
复制内容到剪贴板 程序代码if (img.complete) { // 如果图片已经存在于浏览器缓存，直接调用回调函数
callback(img);
return; // 直接返回，不用再处理onload事件
}
关于这段代码，看相关博文里的叙述，原因如下：
引用内容经过对多个浏览器版本的测试，发现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的调用。

+ 查看当前日志评论 (0)

登录

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 1.037 ms

返回

标题: 关于图片的预加载,你所不知道的

你没有权限发表评论

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 1.037 ms

返回

暂无评论

返回

────────────

木子屋

PJBlog3 v3.2.9.518 Inside.

Processed In 1.084 ms

返回