在平常的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只是爲了說明方便,實際開發中通常不會這麼作,只要作到移除元素完不成的那部分任務便可。
以上就是總結的對象銷燬時須要額外注意的三種狀況,固然還有其餘更多狀況,但大致與之相似。
讓代碼有自我意識,從學會自我銷燬開始。