>  기사  >  웹 프론트엔드  >  img.onload에 대한 지식 포인트는 무엇입니까?

img.onload에 대한 지식 포인트는 무엇입니까?

一个新手
一个新手원래의
2017-09-11 09:04:482204검색

머리말:
onload를 사용할 때 우리는 항상 다양한 브라우저에서 다양한 제안과 다양한 성능을 볼 수 있습니다. 다른 사람들이 요약한 이러한 경험은 모두 끊임없이 코드를 입력하고 끊임없이 시행착오, 테스트 및 최적화를 통해서만 달성할 수 있습니다. 구덩이에서 기어나오세요. 이해하지 못하는 것을 만났을 때, 그것을 알아내려고 노력하고 몇 번 타이핑하면 그 지식은 당신의 것이 될 것입니다. 저의 겸손한 의견~_~, 더 이상 헛소리는 하지 마세요...

먼저 코드를 보세요:

<body>
    <p class="box">
     <p> 1111</p>
    </p>
    <script type="text/javascript">    function loadImage(url, callback) {
        //创建一个Image对象,实现图片的预下载
        var img = new Image();
            img.src = url;
        console.log(&#39;----111----&#39;);        // 如果图片已经存在于浏览器缓存,直接调用回调函数
        if (img.complete) {
            callback(img);            // 直接返回,不用再处理onload事件
            return ;
        }
        img.onload = function() {
            console.log(&#39;----333----&#39;);             //图片下载完毕时异步调用callback函数
            callback(img);
        }
        console.log(&#39;----222----&#39;);
    }    function call(img) {
        // 有权访问另一个函数作用域内变量的函数都是闭包
        $(img).appendTo(&#39;.box&#39;);
    }
     loadImage(&#39;https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1504976397726&di=62045a300551dd62608d3e9423221c1f&imgtype=0&src=http%3A%2F%2Fp9.qhmsg.com%2Ft01ffd2fe0a1210db89.png&#39;,call);  
    //loadImage(&#39;./img/bird.png&#39;, call);
    </script>
[闭包概念讲解](http://www.cnblogs.com/wangfupeng1988/p/3994065.html)分析以上代码:
这个方法功能是ok的,但是有一些隐患。1  创建了一个临时匿名函数来作为图片的onload事件处理函数,形成了闭包。
相信大家都看到过ie下的内存泄漏模式的文章,其中有一个模式就是循环引用,而闭包就有保存外部运行环境的能力(依赖于作用域链的实现),所以 img.onload这个函数内部又保存了对img的引用,这样就形成了循环引用,导致内存泄漏。(这种模式的内存泄漏只存在低版本的ie6中,打过补丁 的ie6以及高版本的ie都解决了循环引用导致的内存泄漏问题)。
**这里有点类似于Object-c中block和self的Strong Reference cycle,即循环强引用,self引用了block,block中又用到了self,各自的引用计数器都为一,都强引用对方,不会销毁,造成内存泄漏。OC中就是把self变为weakSelf来解决,同理我们也要在这里有所作为。**2  只考虑了静态图片的加载,忽略了gif等动态图片,这些动态图片可能会多次触发onload。
要解决上面两个问题很简单,在img.onload中把img.onload=null;
代码如下:
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的complete状态),但是对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的调用。

위 내용은 img.onload에 대한 지식 포인트는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.