Web 前端开发日志(三):HTML 节点的内存泄露问题

文章为在下之前开发时的一些记录与当时的思考, 学习之初的内容总会有所考虑不周, 若是出错还请多多指教.javascript

TL;DR

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 消失了么?函数

用 Memory 抓一下 Heap 看一下

咱们来用 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)
}
复制代码

而后刷新页面,再抓一个新的快照:

此次没了!

问题在哪里?

最先的代码问题出如今了,deleteMyDivmyDiv 进行了引用,并且 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 带来的内存泄漏问题.

相关文章
相关标签/搜索