zoukankan      html  css  js  c++  java
  • 事件绑定持有对象引用导致GC不回收对象

    现象

    封装了一个部门选择框对象,在第一次创建选择框的时候是正确的,但是在关闭之后再次创建,发现点击事件被调用两次,于是console.log(),发现第一次创建的选择框的数据也被打印了一次,执行两次分别是执行了第一次本该销毁掉的选择框对象的方法和刚创建的选择框对象的方法。

    解决

    想了想,会不会是事件绑定持有了对象的引用导致了对象不被GC。
    于是动手:

    1
    2
    <button id="test">test</button>
    <button id="bind">bind</button>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function A(num){
    this.test=function(){
    console.log(num);
    }
    }
    $("#test").click(function(event) {
    var a = new A(Math.random());
    $("#bind").click(function(event) {大专栏  事件绑定持有对象引用导致GC不回收对象v>
    a.test();
    });
    });

    点击两次test,然后点击bind,果然打印了两次,而且num不一样。

    想了一想,只要在第二次绑定之前把之前的事件解绑了就行了。于是在绑定之前加了:

    1
    $("#bind").off("click");

    果然OK了,但是虽然现象是解决的,不知道这个对象是不是真的被销毁了,于是用chrome的profiles看了下。

    验证

    使用Chrome Profiles

    F12开发者选项,选择Profiles选项卡,选择Take Heap Snapshot,点击Take Snapshot即可拍下当前JS的heap快照,每次执行之前都会强制执行一次GC。

    未设置off

    1. 点击test,创建一个A的对象,并绑定bind的点击事件,拍下快照
      image

    2. 再次点击test,拍下快照
      image
      发现之前的对象没有销毁,并且都有一个引用被事件持有。

    3. 查看bind按钮的绑定事件
      image
      可见bind按钮的绑定事件有两个。

    设置off

    1. 点击test,拍下快照
      image

    2. 再次点击test,拍下快照
      image

    3. 查看bind按钮的绑定事件
      image

    发现之前的对象已经销毁 >.<。

    结语

    JS的灵活性既是优点也是缺点,平时写代码时要注意内存泄漏的问题。当代码量非常庞大的时候,就不能仅靠复查代码来排查问题,必须要有一些监控对比工具来协助排查。

  • 相关阅读:
    ES2017 新特性:Async Functions (异步函数)
    为什么 window.location.search 为空?
    vue-cli 构建Vue项目后的打包和发布
    Vue.js父子组件如何传值 通俗易懂
    vue 面试题(文章末尾还有其他链接)
    vue组件命名和传值 and 父子组件传值
    line-gradient 之渐变角度
    vue-router路由模式
    vue-router 去掉#
    记录vue项目上线遇到的一些问题
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12147551.html
Copyright © 2011-2022 走看看