3

我读过一篇关于内存泄漏的文章,其中垃圾收集器逻辑总结为:

  1. 垃圾收集器建立一个“根”列表。根通常是在代码中保存引用的全局变量。在 JavaScript 中,“window”对象是可以充当根的全局变量的一个示例。窗口对象始终存在,因此垃圾收集器可以认为它及其所有子对象始终存在(即不是垃圾)。
  2. 所有根都经过检查并标记为活动的(即不是垃圾)。所有的孩子也被递归地检查。从根可以到达的所有东西都不被视为垃圾。
  3. 所有未标记为活动的内存现在都可以视为垃圾。收集器现在可以释放该内存并将其返回给操作系统。

此外,MDN 声明 DocumentFragment 不是活动DOM 树的一部分。

DocumentFragment 接口表示一个没有父级的最小文档对象。它用作 Document 的轻量级版本,它存储由节点组成的文档结构的一部分,就像标准文档一样。主要区别在于,由于文档片段不是活动文档树结构的一部分,因此对片段所做的更改不会影响文档、导致重排或在进行更改时产生任何性能影响。

一点一点我开始意识到背后的逻辑,但如果有人能对我有所启发,我将不胜感激:),使用下面的示例,并解释原因:

1. 将 DOM 引用无效后被认为是一种很好的做法。用过的。
2. 是否需要取消对 DocumentFragment 和包含它的元素的引用。

function usefulFunction() {
  let existingNode = document.querySelector(`.existing`)
  
  let createdNode = document.createElement(`ul`)
  let fragment = document.createDocumentFragment();
  let browsers = ['Firefox', 'Chrome', 'Opera', 
      'Safari', 'Internet Explorer'];

  browsers.forEach(function(browser) {
      var li = document.createElement('li');
      li.textContent = browser;
      fragment.appendChild(li);
  });
    
  existingNode.appendChild(createdNode)
  createdNode.appendChild(fragment)
  
  fragment = null
  createdNode = null
  existingNode = null
}

usefulFunction()
<div class="existing"></div>

更新的片段

let existingNode

function helperFunction(object) {
  let createdNode = document.createElement(`div`)
  createdNode.innerHTML = `Hello, I am a beautiful div`
  
  existingNode.appendChild(createdNode)
  existingNode = null 
}

function usefulFunction() {
  existingNode = document.querySelector(`.existing`)
  let fragment = document.createDocumentFragment();
  let browsers = ['Firefox', 'Chrome', 'Opera', 
      'Safari', 'Internet Explorer'];

  browsers.forEach(function(browser) {
      var li = document.createElement('li');
      li.textContent = browser;
      fragment.appendChild(li);
  });
      
  existingNode.appendChild(fragment)
  helperFunction()
}


usefulFunction()
<div class="existing"></div>

4

1 回答 1

3

如果你正确使用了局部变量,通常很少需要在使用后将它们无效。当您离开函数的范围时,变量就会消失,并且它们引用的任何对象都不是来自仍在范围内的某个变量的引用,这些对象将成为垃圾。文档片段不从 DOM 中引用,仅从变量中引用,因此当变量被销毁时,可以对片段进行垃圾收集。

这是您应该谨慎使用全局变量的原因之一。它们应该只用于需要随时间持续存在的数据,例如保持应用程序的状态。

请注意,在您的第一个示例代码中,使变量无效对垃圾回收没有影响,因为它们包含的所有节点和片段都已附加到 DOM。但如果不是这样,这些对象将在函数结束后立即成为垃圾,因此无需在返回之前使变量无效。

在第二个片段中,existingNode如果您曾经从 DOM 中删除该元素,则应该取消该元素。否则,全局变量将阻止节点被垃圾回收。但是,如果预计节点在应用程序的整个生命周期内都是永久的,则无需担心变量。

于 2018-08-14T00:11:45.703 回答