javascript - 防止此 javascript 代码中的内存泄漏?

标签 javascript garbage-collection django-admin

我有一个嵌套类别列表的 Django 管理页面,如下所示: alt text

我写了这个脚本来对列表进行排序并分层呈现:

{% extends "admin/change_list.html" %}
{% load i18n %}
{% block footer %}

<script>
(function(){

  var rows=document.getElementById('result_list').getElementsByTagName('tr'),
      table=rows[1].parentNode||rows[1].parentElement,
      i=0, r,      // skip the first row
      data={};     // store category data

  while (r=rows[++i]) {
    var catName=r.getElementsByTagName('a')[0],
        k=catName.innerHTML,
        opts=r.getElementsByTagName('select')[0],
        j=-1, opt;
    while (opt=opts[++j]) {
      if (!opt.selected) continue;
      data[k] = {  
        title:        k,
        children:     {},
        parentName:   opt.innerHTML, 
        parentId:     opt.value, 
        catName:      catName,
        row:          r
      } 
    }
  }

  for (var sub in data) {
    if (data[sub].parentName == sub) continue;
    for (var sup in data) {
      if (sup == data[sub].parentName) {
        data[sup].children[sub]=data[sub];
        data[sub].parent = data[sup];
        break;
      }
    }
  }

  var alt = 0;
  for (var leaf in data) {
    if (data[leaf].parentName != leaf) continue;
    walk(data[leaf], leaf, function (node, nodeName) {
      var n=node, t=n.title;
      while (n=n.parent) {
        t = ' &middot; &nbsp;' + t;
      }
      node.catName.innerHTML = t;
      node.row['class']=node.row['className']='row'+alt++%2;
      table.removeChild(node.row);
      table.appendChild(node.row);
    });
  }

  function walk (leaf, leafName, cb) {
    if (cb) cb(leaf, leafName);
    leaf.ready = true;
    for (var kid in leaf.children) {
      if (leaf.children[kid].ready) continue;
      walk(leaf.children[kid], kid, cb);
    }
  }

}());
</script>

{% endblock %}

...脚本运行良好,列表如下所示: alt text

我的问题是:我觉得脚本在垃圾回收较弱的 UA 中容易出现内存泄漏,因为父/子内容创建的循环引用。这是我应该担心的事情吗?有没有更好的方法来编写脚本?我应该在脚本末尾删除一堆东西吗?如果是,怎么办?

最佳答案

我看到一些小漏洞,IE 垃圾收集器在清理函数内的事件节点引用时出现问题。这是因为 DOM 和 JavaScript 都有自己的垃圾收集器,基本上,它们不想为了引用而互相争吵。

既然你每页调用一次这个脚本?内存泄漏很小,实际上可以忽略,除非人们在一次 session 中打开 100 多个页面。不过清理起来更好。

{% extends "admin/change_list.html" %}
{% load i18n %}
{% block footer %}

<script>
(function(){

  var rows=document.getElementById('result_list').getElementsByTagName('tr'),
      table={},
      i=0, r,      // skip the first row
      data={};     // store category data

  // table is now a JS object with a el reference to an element.
  table.el = rows[1].parentNode||rows[1].parentElement;

  while (r=rows[++i]) { // you skip the first row, that correct? Else use i++
    var catName=r.getElementsByTagName('a')[0],
        k=catName.innerHTML,
        opts=r.getElementsByTagName('select')[0],
        j=-1, opt;
    while (opt=opts[++j]) {
      if (!opt.selected) continue;
      data[k] = {  
        title:        k,
        children:     {},
        parentName:   opt.innerHTML, 
        parentId:     opt.value, 
        catName:      catName,
        row:          r
      } 
    }
  }
  // nullify node references
  r = catName = opt = rows =  null;

  for (var sub in data) {
    if (data[sub].parentName == sub) continue;
    for (var sup in data) {
      if (sup == data[sub].parentName) {
        data[sup].children[sub]=data[sub];
        data[sub].parent = data[sup];
        break;
      }
    }
  }

  var alt = 0;
  for (var leaf in data) {
    if (data[leaf].parentName != leaf) continue;
    walk(data[leaf], leaf, function (node, nodeName) {
      var n=node, t=n.title;
      while (n=n.parent) {
        t = ' &middot; &nbsp;' + t;
      }
      node.catName.innerHTML = t;
      node.row['class']=node.row['className']='row'+alt++%2;
      // if table wasn't a JS object, this closure would not have been cleaned up.
      // a refence to table is kept, not to a live DOM element.
      table.el.removeChild(node.row);
      table.el.appendChild(node.row);
    });
  }


  function walk (leaf, leafName, cb) {
    if (cb) cb(leaf, leafName);
    leaf.ready = true;
    for (var kid in leaf.children) {
      if (leaf.children[kid].ready) continue;
      walk(leaf.children[kid], kid, cb);
    }
  }

}());
</script>

{% endblock %}

整理起来有点困惑,因为您的 JS 对象名称暗示它们是 DOM 元素 =P 但我认为我猜对了。但是您可能想要检查代码并使我可能忽略的其他 DOM 元素无效(当然,一旦您完成了它们)。

关于javascript - 防止此 javascript 代码中的内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3645386/

相关文章:

没有jquery的javascript可折叠表格

javascript - d3.js 更新视觉

javascript - 更改没有名称的属性的处理程序

android - 垃圾收集 Activity

Django 管理员 - FORCE_SCRIPT_NAME 在 POST 时附加到 URL 两次

python - 无法解析余数 : '!=None' from '!=None' | Django Admin

javascript - 如何使用 Flask 将 Canvas url 转换为图像 numpy 数组?

c# - 使困惑。 CA1063错了吗? GC.SuppressFinalize(这个)

c# - Main 方法的垃圾收集(无限循环)

python - Django ModelAdmin 中的 "list_display"可以显示 ForeignKey 字段的属性吗?