代码之家  ›  专栏  ›  技术社区  ›  Dagg Nabbit

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

  •  2
  • Dagg Nabbit  · 技术社区  · 14 年前

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

    我编写此脚本是为了对列表进行排序并按层次结构呈现:

    %extends“admin/change_list.html”%
    {%加载I18N%}
    %块页脚%
    
    脚本& GT;
    (函数){
    
    var rows=document.getElementByID('result_list').getElementsByTagname('tr'),
    table=rows[1].父节点行[1].父元素,
    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])。{
    如果(!)选择)继续;
    数据[k]={
    标题:K,
    儿童:,
    父名:opt.innerhtml,
    parentID:选项值,
    类别名称:类别名称,
    行:R
    }
    }
    }
    
    用于(数据中的var sub){
    if(data[sub].parentname==sub)继续;
    对于(数据中的var sup){
    if(sup==data[sub].parentname){
    data[sup].children[sub]=data[sub];
    data[sub].parent=data[sup];
    断裂;
    }
    }
    }
    
    VaR ALT=0;
    for(数据中的var叶){
    if(数据[leaf].parentname!=叶)继续;
    walk(数据[叶],叶,函数(节点,节点名){
    var n=节点,t=n.标题;
    而(n=n.父){
    t='· '+t;
    }
    node.catname.innerhtml=t;
    node.row['class']=node.row['classname']='row'+alt++%2;
    表.removechild(node.row);
    table.appendchild(node.row);
    (});
    }
    
    功能漫游(leaf、leafname、cb){
    如果(cb)cb(leaf,leafname);
    leaf.ready=真;
    用于(叶中的var kid.children){
    if(leaf.children[kid].ready)继续;
    步行(leaf.children[kid],kid,cb);
    }
    }
    
    }());
    & /脚本& GT;
    
    %端块%}
    < /代码> 
    
    

    …脚本运行良好,列表如下:

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

    我编写此脚本是为了对列表进行排序并按层次结构呈现:

    {% 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

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

    2 回复  |  直到 14 年前
        1
  •  1
  •   BGerrissen    14 年前

    我看到一些小的泄漏,即垃圾收集器在清理函数内部的活动节点引用时遇到问题。这是因为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 %}
    

    排序有点混乱,因为您的JS对象名意味着它们是dom元素=p,但我认为我正确地理解了它。但是,您可能希望检查代码并使我可能忽略的其他DOM元素无效(当然,一旦完成了这些元素的工作)。

        2
  •  1
  •   Stefan    14 年前

    剧本没有 似乎 包含任何严重的内存泄漏,因为它不会留下任何 功能 (像cb)在 步行 . 所以垃圾收集器应该成功地收集所有创建的垃圾。

    但是,您可能有很高的内存使用率 在期间 如果迭代次数真的很高,则执行。

    [我以前写过一篇关于这个的业余文章] http://stefan.artspace44.com/javascript/memory-leaks/