关于图片的预加载过程中隐藏未知的


Posted in Javascript onDecember 19, 2012

看完了曼联与曼城的同城德比,还有漫长的两个小时,才能看到期待中的国家德比。无聊的很,左右无事,便来论坛闲逛。看到了一章关于图片预加载的博文,其代码如下:

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的调用。
Javascript 相关文章推荐
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
Apr 12 Javascript
Jquery升级新版本后选择器的语法问题
Jun 02 Javascript
JavaScript类和继承 prototype属性
Sep 03 Javascript
Jquery进度条插件 Progress Bar小问题解决
Jul 12 Javascript
关于jQuery新的事件绑定机制on()的使用技巧
Apr 26 Javascript
node.js中的fs.fstatSync方法使用说明
Dec 15 Javascript
再谈JavaScript线程
Jul 10 Javascript
Spring mvc 接收json对象
Dec 10 Javascript
JavaScript 实现的 zip 压缩和解压缩工具包Zip.js使用详解
Dec 14 Javascript
jQuery控制frames及frame页面JS的方法
Mar 08 Javascript
JavaScript实现Base64编码转换
Apr 23 Javascript
JavaScript之创意时钟项目(实例讲解)
Oct 23 Javascript
给页面渲染时间加速 干掉Dom Level 0 Event
Dec 19 #Javascript
img onload事件绑定各浏览器均可执行
Dec 19 #Javascript
JavaScript实现快速排序(自已编写)
Dec 19 #Javascript
js 使用form表单select类实现级联菜单效果
Dec 19 #Javascript
JS限制上传图片大小不使用控件在本地实现
Dec 19 #Javascript
JS上传图片前的限制包括(jpg jpg gif及大小高宽)等
Dec 19 #Javascript
js限制文本框输入长度两种限制方式(长度、字节数)
Dec 19 #Javascript
You might like
PHP中文处理 中文字符串截取(mb_substr)和获取中文字符串字数
2011/11/10 PHP
从刷票了解获得客户端IP的方法
2015/09/21 PHP
form表单传递数组数据、php脚本接收的实例
2017/02/09 PHP
基于swoole实现多人聊天室
2018/06/14 PHP
javascript Base类 包含基本的方法
2009/07/22 Javascript
使用Microsoft Ajax Minifier减小JavaScript文件大小的方法
2010/04/01 Javascript
jQuery 表单验证扩展代码(二)
2010/10/20 Javascript
ASP.NET jQuery 实例5 (显示CheckBoxList成员选中的内容)
2012/01/13 Javascript
Javascript基础 函数“重载” 详细介绍
2013/10/25 Javascript
jQuery实现下拉框选择图片功能实例
2015/08/08 Javascript
怎么限制input的text里输入的值只能是数字(正则、js)
2016/05/16 Javascript
Javascript缓存API
2016/06/14 Javascript
JavaScript 闭包机制详解及实例代码
2016/10/10 Javascript
jQuery菜单实例(全选,反选,取消)
2017/08/28 jQuery
RxJS的入门指引和初步应用
2019/06/15 Javascript
vue实现权限控制路由(vue-router 动态添加路由)
2019/11/04 Javascript
electron踩坑之remote of undefined的解决
2020/10/06 Javascript
JS如何调用WebAssembly编译出来的.wasm文件
2020/11/05 Javascript
[46:55]Ti4 冒泡赛第二轮 LGD vs C9
2014/07/14 DOTA
[39:08]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第一场 12.12
2020/12/16 DOTA
python中私有函数调用方法解密
2016/04/29 Python
Python变量和数据类型详解
2017/02/15 Python
在python3.5中使用OpenCV的实例讲解
2018/04/02 Python
python spyder中读取txt为图片的方法
2018/04/27 Python
python将pandas datarame保存为txt文件的实例
2019/02/12 Python
pandas条件组合筛选和按范围筛选的示例代码
2019/08/26 Python
Python使用matplotlib实现交换式图形显示功能示例
2019/09/06 Python
Python MOCK SERVER moco模拟接口测试过程解析
2020/04/13 Python
Python单元测试及unittest框架用法实例解析
2020/07/09 Python
Python 如何展开嵌套的序列
2020/08/01 Python
网站编辑求职信
2013/10/17 职场文书
总账会计岗位职责
2014/03/13 职场文书
村庄环境整治方案
2014/05/15 职场文书
2015商场元旦促销活动策划方案
2014/12/09 职场文书
房地产销售主管岗位职责
2015/02/13 职场文书
Python实现单例模式的5种方法
2021/06/15 Python