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


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 相关文章推荐
Discuz! 6.1_jQuery兼容问题
Sep 23 Javascript
基于jquery实现的移入页面上空文本框时,让它变为焦点,移出清除焦点
Jul 26 Javascript
js使用ajax读博客rss示例
May 06 Javascript
jQuery实现的经典滑动门效果
Sep 22 Javascript
JavaScript高级教程5.6之基本包装类型(详细)
Nov 23 Javascript
JS表单数据验证的正则表达式(常用)
Feb 18 Javascript
解决Vue编译时写在style中的路径问题
Sep 21 Javascript
jQuery实现checkbox的简单操作
Nov 18 jQuery
js 判断一个数字是不是2的n次方幂的实例
Nov 26 Javascript
vue+axios新手实践实现登陆的示例代码
Jun 06 Javascript
如何利用vue+vue-router+elementUI实现简易通讯录
May 13 Javascript
使用Vue实现简单计算器
Feb 25 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
array_multisort实现PHP多维数组排序示例讲解
2011/01/04 PHP
用PHP实现 上一篇、下一篇的代码
2012/09/29 PHP
163的邮件用phpmailer发送(实例详解)
2013/06/24 PHP
PHP四舍五入精确小数位及取整
2014/01/14 PHP
PHP使用feof()函数读文件的方法
2014/11/07 PHP
php 从一个数组中随机的取出若干个不同的数实例
2016/12/31 PHP
php分页查询的简单实现代码
2017/03/14 PHP
jQuery Flash/MP3/Video多媒体插件
2010/01/18 Javascript
用JavaScript对JSON进行模式匹配(Part 1-设计)
2010/07/17 Javascript
js中判断对象是否为空的三种实现方法
2013/12/23 Javascript
浅谈JavaScript中的string拥有方法的原因
2015/08/28 Javascript
Bootstrap导航栏各元素操作方法(表单、按钮、文本)
2015/12/28 Javascript
全面了解JavaScript的数据类型转换
2016/07/01 Javascript
AngularJS折叠菜单实现方法示例
2017/05/18 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
浅谈js基础数据类型和引用类型,深浅拷贝问题,以及内存分配问题
2017/09/02 Javascript
Node.js 使用流实现读写同步边读边写功能
2017/09/11 Javascript
vue中的$emit 与$on父子组件与兄弟组件的之间通信方式
2018/05/13 Javascript
解决linux下node.js全局模块找不到的问题
2018/05/15 Javascript
JavaScript如何判断input数据类型
2020/02/06 Javascript
JS面向对象编程基础篇(一) 对象和构造函数实例详解
2020/03/03 Javascript
JavaScript 类的封装操作示例详解
2020/05/16 Javascript
Vue3不支持Filters过滤器的问题
2020/09/24 Javascript
[44:51]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第二场
2018/04/05 DOTA
python通过pil将图片转换成黑白效果的方法
2015/03/16 Python
Python使用itertools模块实现排列组合功能示例
2018/07/02 Python
python实现点击按钮修改数据的方法
2019/07/17 Python
python3实现单目标粒子群算法
2019/11/14 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
2021/03/03 Python
京东奢侈品:全球奢侈品牌
2018/03/17 全球购物
迷你唐卡软皮鞋:Minnetonka Moccasin
2018/05/01 全球购物
什么是Linux虚拟文件系统VFS
2012/01/31 面试题
手工社团活动方案
2014/02/17 职场文书
职业生涯规划书怎么写?
2014/09/14 职场文书
详解Python生成器和基于生成器的协程
2021/06/03 Python
python中的class_static的@classmethod的巧妙用法
2021/06/22 Python