一篇文章带你搞懂JS对象的自我销毁

在平常的JS组件开发中,每每会有一些较为复杂的DOM操做及事件监听,尤为是在处理UI层面的widgets时候更为明显。经常会花不少精力在对象的init上,而当组件须要被移除时则仅仅是把所在DOM草草的remove掉就算完事儿。css

固然,绝大多数状况这样处理并无什么不妥,由于事件监听时仅仅局限于所属的DOM自身,移除DOM后,只要对象的外部引用再也不维系,相关的内存占用很快就会被看成垃圾回收掉(本文不讨论低版本 IE 内存回收的 BUG)。html

其实我的在构建组件(对象)的时候是比较习惯于添加自定义方法destroy,用来手动销毁对象内部的一些引用。也就是今天要说的仅靠移除DOM并不能达到销毁对象的几种状况。前端

当你的组件出现下面几种状况时须要特别注意。vue

一: DOM事件监听越界 常规状况下,一个组件须要监听的仅仅是自身的DOM内的事件。偶尔也会有另外一种状况,对象不得不操做自身以外的DOM。node

拿常见的瀑布流组件为例,除了自身事件,还要监听页面的滚动、浏览器尺寸重置等事件。所以当瀑布流组件须要被移除时,简单的移除自身DOM并不能完整销毁组件对页面的影响。jquery

下面是常规作法的例子:webpack

//定义瀑布流组件
function WaterFall(node){
  this.node = node;
  window.addEventListener('scroll',function(){
    //do sth
    console.log('scrolling');
  });
}
//实例化一个瀑布流组件
var node_content = document.getElementById('xxx');
new WaterFall(node_content);
//移除瀑布流组件所属的DOM
node_content.parentNode.removeChild(node_content);
复制代码

上面的例子很明显,移除DOM后遗留的事件监听还在,回调内对组件的引用会致使整个组件常驻内存没法被回收,直至页面卸载。web

不过你可能会说,在移除DOM时顺手解除下事件绑定就 OK 啦。事实确实如此,可是若是操做的具体细节让调用者实现就有点儿麻keng烦die了。所以咱们须要提供一个destroy接口让调用者去解除对窗口滚动等事件的监听。面试

//定义瀑布流组件
function WaterFall(node){
  this.node = node;
  this._scrollListenner = function(){
    //do sth
    console.log('scrolling');
  };
  window.addEventListener('scroll',this._scrollListenner);
}                                                   //欢迎加入前端全栈开发交流圈一块儿学习交流:1007317281
WaterFall.prototype.destroy = function(){
    window.removeEventListener('scroll',this._scrollListenner);
    this.node.parentNode.removeChild(this.node);
};

//实例化一个瀑布流组件
var myWaterFall = new WaterFall(document.getElementById('xxx'));
//注销瀑布流组件
myWaterFall.destroy();
复制代码

给你们推荐一个技术交流学习圈,里面归纳移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。获取资料👈👈👈 对web开发技术感兴趣的同窗,能够加入👉👉👉交流圈👈👈👈,无论你是小白仍是大牛都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时天天更新视频资料。ajax

二:JS 生命周期过长 一部分场景下,某段 JS 会在整个生命周期中反复被调用。好比轮播图自动播放,倒计时时钟的重绘。不管是使用setInterval不断调取,或者是 setTimeout递归延时。这二者在对象自身DOM被移除时一样不会随之被清除。所以也须要对象在被销毁时手动解除定时器。

//定义倒计时组件
function Countdown(node){
  this.node = node;
  this._timerId = setInterval(function(){
    //do sth
    console.log('recount');
  },500);
}                                              //欢迎加入前端全栈开发交流圈一块儿学习交流:1007317281
Countdown.prototype.destroy = function(){
    clearInterval(this._timerId);
    this.node.parentNode.removeChild(this.node);
};

//实例化一个倒计时组件
var myCountdown = new Countdown(document.getElementById('yyy'));
//注销倒计时组件
myCountdown.destroy();
复制代码

三:DOM 以外的异步事件 比较常见的情形就是 ajax。当一个请求结束以前对象被销毁,ajax 返回后的操做无需继续进行。也有必定风险由于 dom 已被移除致使操做报错。

以渲染数据为例,ajax部分使用jquery:

//定义列表组件
function UserList(node){
  this.node = node;
  this._ajax = $.ajax(/** **/);
}                                               //欢迎加入前端全栈开发交流圈一块儿学习交流:1007317281
UserList.prototype.destroy = function(){
    //取消请求发送
    this._ajax.abort();
    this.node.parentNode.removeChild(this.node);
};

//实例化一个列表组件
var myUserList = new Countdown(document.getElementById('yyy'));
//注销列表组件
myUserList.destroy();
复制代码

上面例子中,destroy方法内部移除DOM只是为了说明方便,实际开发中通常不会这么作,只要作到移除元素完不成的那部分任务便可。

以上就是总结的对象销毁时须要额外注意的三种状况,固然还有其余更多状况,但大致与之相似。

让代码有自我意识,从学会自我销毁开始。

相关文章
相关标签/搜索