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


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 相关文章推荐
用javascript获取当页面上鼠标光标位置和触发事件的对象的代码
Dec 09 Javascript
关于flash遮盖div浮动层的解决方法
Jul 17 Javascript
js异常捕获方法介绍
Apr 10 Javascript
原生javascript实现图片滚动、延时加载功能
Jan 12 Javascript
浅析BootStrap模态框的使用(经典)
Apr 29 Javascript
Javascript之Date对象详解
Jun 07 Javascript
原生Javascript插件开发实践
Jan 18 Javascript
jQuery实现文字超过1行、2行或规定的行数时自动加省略号的方法
Mar 28 jQuery
详解如何配置vue-cli3.0的vue.config.js
Aug 23 Javascript
JavaScript使用闭包模仿块级作用域操作示例
Jan 21 Javascript
使用JavaScript和MQTT开发物联网应用示例解析
Aug 07 Javascript
VSCode插件安装完成后的配置(常用配置)
Aug 24 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中通过加号合并数组的一个简单方法分享
2011/01/27 PHP
cakephp打印sql语句的方法
2015/02/13 PHP
ThinkPHP的SAE开发相关注意事项详解
2016/10/09 PHP
Yii框架防止sql注入,xss攻击与csrf攻击的方法
2016/10/18 PHP
解决JS浮点数运算出现Bug的方法
2013/03/12 Javascript
javascript中强制执行toString()具体实现
2013/04/27 Javascript
js实现数组去重、判断数组以及对象中的内容是否相同
2013/11/29 Javascript
关于img的href和src取变量及赋值的方法
2014/04/28 Javascript
JavaScript清空数组元素的两种方法简单比较
2015/07/10 Javascript
实例代码讲解jquery easyui动态tab页
2015/11/17 Javascript
实例解析jQuery插件EasyUI最常用的表单验证规则
2015/11/29 Javascript
深入浅析javascript中的作用域(推荐)
2016/07/19 Javascript
jQuery自适应轮播图插件Swiper用法示例
2016/08/24 Javascript
js 发布订阅模式的实例讲解
2017/09/10 Javascript
jQuery实现的鼠标响应缓冲动画效果示例
2018/02/13 jQuery
vue数组对象排序的实现代码
2018/06/20 Javascript
vue: WebStorm设置快速编译运行的方法
2018/10/18 Javascript
详解JavaScript中的数据类型,以及检测数据类型的方法
2020/09/17 Javascript
vue使用exif获取图片经纬度的示例代码
2020/12/11 Vue.js
简单谈谈python的反射机制
2016/06/28 Python
简单谈谈Python中的元祖(Tuple)和字典(Dict)
2017/04/21 Python
从numpy数组中取出满足条件的元素示例
2019/11/26 Python
Python处理mysql特殊字符的问题
2020/03/02 Python
Python批量将图片灰度化的实现代码
2020/04/11 Python
关于python tushare Tkinter构建的简单股票可视化查询系统(Beta v0.13)
2020/10/19 Python
python3爬虫中多线程进行解锁操作实例
2020/11/25 Python
赫里福德的一家乡村零售商店:Philip Morris & Son
2017/06/25 全球购物
英国川宁茶官方网站:Twinings茶
2019/05/21 全球购物
文言文形式的学生求职信
2013/12/03 职场文书
百年校庆节目主持词
2014/03/27 职场文书
律师授权委托书范本
2014/10/07 职场文书
国际贸易实务实训报告
2014/11/05 职场文书
教师节老师寄语
2015/05/28 职场文书
反四风问题学习心得体会
2016/01/22 职场文书
将图片保存到mysql数据库并展示在前端页面的实现代码
2021/05/02 MySQL
python3.7.2 tkinter entry框限定输入数字的操作
2021/05/22 Python