文章爲在下之前開發時的一些記錄與當時的思考, 學習之初的內容總會有所考慮不周, 若是出錯還請多多指教.javascript
對 DOM
節點的引用會使得節點一直在內存中存儲而不會進行釋放.html
請各位考慮一下以下代碼,這裏有一個簡易的 HTML:java
<div id="my-div">
<span>My Div</span>
<ul>
<li>Hero</li>
<li>Cows</li>
<li>Bugs</li>
</ul>
</div>
<button onclick="deleteMyDiv()">Delete My Div</button>
複製代碼
還有一段比較醜的邏輯:typescript
<script> const myDiv = document.querySelector('#my-div') function deleteMyDiv () { myDiv.parentElement.removeChild(myDiv) } </script>
複製代碼
請問,點擊 "Delete My Div" 按鈕時,節點 #my-div
消失了麼?函數
咱們來用 Chrome 開發者工具中抓一下 Heap 觀察一下,看看是否是能找到 Detached DOM
.工具
Detached DOM
表明一個 HTML 節點在 HTML 中被移除,但在內存中還保持引用的狀態,意思就是,沒刪乾淨側漏啦!性能
咱們來實際抓一下看看,咱們抓兩次快照,第一次是在點擊刪除按鈕前的快照,以下圖:學習
咱們在搜索框中輸入 detached
,看起來並無 Detached 節點.ui
咱們點擊頁面中的 "Delete My Div" 後來抓第二次:spa
嚯,這就有了!選中它看看:
看看這個 div#my-div
,I'm angry!
咱們來稍微調整一下邏輯:
function getMyDiv () {
return document.querySelector('#my-div')
}
function deleteMyDiv () {
const myDiv = getMyDiv()
myDiv.parentElement.removeChild(myDiv)
}
複製代碼
而後刷新頁面,再抓一個新的快照:
此次沒了!
最先的代碼問題出如今了,deleteMyDiv
對 myDiv
進行了引用,並且 deleteMyDiv
沒有進行回收,因此致使 myDiv
的一直存在.
咱們再仔細看如下剛纔截取的快照:
就算是將 myDiv
從 HTML 中刪除,內存中也會一直保存其數據不會釋放.
修改以後的代碼沒有任何地方保持了對 myDiv
的引用,因此在刪除操做執行完畢後會馬上釋放 div#my-div
節點.
實際上這樣的狀況在業務邏輯中很是容易出現,好比建立一個比較複雜的節點,這個節點中包含了不少細碎的節點,甚至這些節點是從別的業務服務中傳入進來的,這時就很難保證這些細碎的節點沒有被其建立函數或外部代碼引用,因此就算在 HTML 中刪除,也頗有可能形成泄漏.
若是刪除一個節點,這個節點沒有被直接引用,但裏面的子節點被引用,會怎麼樣?
<div id="my-div">
<div id="inner-div">Inner DIV</div>
</div>
<button onclick="deleteMyDiv()">Delete My Div</button>
複製代碼
// 加入 innerDiv.
const innerDiv = document.querySelector('#inner-div')
function getInnerDiv () {
return innerDiv
}
// 下邊仍是以前的代碼.
function getMyDiv () {
return document.querySelector('#my-div')
}
function deleteMyDiv () {
const myDiv = getMyDiv()
myDiv.parentElement.removeChild(myDiv)
}
複製代碼
截取快照:
能夠看到兩個都已經變成 Detached Dom
,批判一番!🐸🔫
實際上在下對於這種狀況在下目前並無很是好的預防實踐,只能說你們對敏感的 DOM 操做邏輯進行謹慎地編寫,並在出現問題的時候藉助工具快速排查,若是有更好的實踐還請你們多分享交流.
對於性能要求比較高的場景,使用原生代碼建立節點仍是請當心謹慎,避免 Detached Dom
帶來的內存泄漏問題.