Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/436.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
防止此javascript代码中的内存泄漏?_Javascript_Garbage Collection_Django Admin - Fatal编程技术网

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

防止此javascript代码中的内存泄漏?,javascript,garbage-collection,django-admin,Javascript,Garbage Collection,Django Admin,我有一个Django管理页面,用于嵌套类别列表,如下所示: 我编写此脚本是为了对列表进行排序并按层次显示: {% extends "admin/change_list.html" %} {% load i18n %} {% block footer %} <script> (function(){ var rows=document.getElementById('result_list').getElementsByTagName('tr'), table=r

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

我编写此脚本是为了对列表进行排序并按层次显示:

{% 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 %}
{%extends“admin/change\u list.html”%}
{%load i18n%}
{%block footer%}
(功能(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
table=行[1]。parentNode | |行[1]。parentElement,
i=0,r,//跳过第一行
data={};//存储类别数据
而(r=行[++i]){
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1,opt;
而(opt=opts[++j]){
如果(!opt.selected)继续;
数据[k]={
标题:k,
儿童:{},
父名称:opt.innerHTML,
parentId:opt.value,
猫名:猫名,
行:r
} 
}
}
用于(数据中的var子项){
如果(data[sub].parentName==sub)继续;
用于(var辅助数据){
if(sup==数据[sub].parentName){
数据[sup]。子项[sub]=数据[sub];
数据[sub]。父项=数据[sup];
打破
}
}
}
var-alt=0;
for(数据中的变量叶){
如果(数据[leaf].parentName!=leaf)继续;
漫游(数据[叶]、叶、函数(节点、节点名){
var n=节点,t=标题;
while(n=n.parent){
t='·;'+t;
}
node.catName.innerHTML=t;
node.row['class']=node.row['className']='row'+alt++%2;
table.removeChild(node.row);
table.appendChild(node.row);
});
}
功能漫游(叶、叶名称、cb){
如果(cb)cb(叶,叶名称);
leaf.ready=true;
for(叶中的变量kid.childs){
如果(leaf.children[kid].ready)继续;
步行(叶.儿童[儿童],儿童,cb);
}
}
}());
{%endblock%}
…脚本运行正常,列表如下所示:

我的问题是:我觉得由于父/子对象创建的循环引用,在垃圾收集较弱的UAs中,脚本很容易出现内存泄漏。这是我应该担心的吗?有没有更好的方法来写剧本?我应该删除脚本末尾的一堆东西吗?如果是,是什么

脚本似乎没有包含任何严重的内存泄漏,因为在行走之后,它没有留下任何函数(如cb)。因此,垃圾收集器应该成功地收集所有创建的垃圾

但是,如果迭代次数非常多,那么在执行过程中可能会有较高的内存使用率

[不久前我写了一篇关于这个的文章]

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

既然你每页调用一次这个脚本?内存泄漏很小,实际上可以忽略,除非人们在一次会话中打开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 %}
{%extends“admin/change\u list.html”%}
{%load i18n%}
{%block footer%}
(功能(){
var rows=document.getElementById('result_list').getElementsByTagName('tr'),
表={},
i=0,r,//跳过第一行
data={};//存储类别数据
//table现在是一个JS对象,具有对元素的el引用。
table.el=行[1]。parentNode | |行[1]。parentElement;
当(r=rows[++i]){//跳过第一行时,正确吗?否则使用i++
var catName=r.getElementsByTagName('a')[0],
k=catName.innerHTML,
opts=r.getElementsByTagName('select')[0],
j=-1,opt;
而(opt=opts[++j]){
如果(!opt.selected)继续;
数据[k]={
标题:k,
儿童:{},
父名称:opt.innerHTML,
parentId:opt.value,
猫名:猫名,
行:r
} 
}
}
//取消节点引用
r=catName=opt=rows=null;
用于(数据中的var子项){
如果(data[sub].parentName==sub)继续;
用于(var辅助数据){
if(sup==数据[sub].parentName){
数据[sup]。子项[sub]=数据[sub];
数据[sub]。父项=数据[sup];
打破
}
}
}
var-alt=0;
for(数据中的变量叶){
如果(数据[leaf].parentName!=leaf)继续;
漫游(数据[叶]、叶、函数(节点、节点名){
var n=节点,t=标题;
while(n=n.parent){
t='·;'+t;
}
node.catName.innerHTML=t;
node.row['class']=node.row['className']='row'+alt++%2;
//若表不是JS对象,那个么这个闭包就不会被清理。
//保留对表的引用,而不是对活动DOM元素的引用。
table.el.removeChild(node.row);
table.el.appendChild(node.row);
});
}
功能漫游(叶、叶名称、cb){
如果(cb)cb(叶,叶名称);
leaf.ready=true;
for(叶中的变量kid.childs){
如果(leaf.children[kid].ready)继续;
步行(叶.儿童[儿童],儿童,cb);
}
}
}());
{%endblock%}

整理起来有点混乱,因为您的JS对象名称暗示它们是DOM elements=p,但我认为我正确地理解了它。但是,您可能想检查一下代码并清空我可能忽略的其他DOM元素(当然,一旦您处理完它们)。

您“感觉”脚本容易出现内存泄漏,或者您观察到内存泄漏?我没有观察到任何内存泄漏,但我感觉IE可能会做一些愚蠢的事情,比如在页面导航时不进行垃圾收集。不幸的是,我没有办法测试那个ATM。你们的操作系统允许你们观察RAM的使用情况吗?如果是这样的话,我相信你可以设置一个原始测试,看看是否有多余的内存泄漏……事实上,我想我可以使用google chrome中的
about:memory
来非常有效地做到这一点。我最担心的是