避免DOM对象内存泄漏的使用准则

终于,整理了一下在WEB前端脚本开发时因DOM对象造成的内存泄漏原因及解决方案。

避免DOM对象内存泄漏的使用准则

  1. 取自DOM元素的DOM对象,添加属性时,属性值不能是与该DOM对象同作用域下声明的函数,如:a.b=function(){};"

    可选方案:
    1. var b = function(){};(function(){var a = DOMNode;a.b = b;}());
    2. var ret = {b:function(){},init:function(){var a = DOMNode;a.b = ret.b;};
     
  2. 如果该DOM对象被其他对象(如:b)引用,该DOM对象的属性值不能包含有对象b,如:b.push(a);a.b=b;

    可选方案:
    1.var data={};b.push(a);a.setAttribute('GUID') = GUID;data[a.getAttribute('GUID')][b] = b;
     
  3. DOM对象属性值不能显式的引用自己,即,不能在该DOM对象生成的作用域进行显式赋值,如:a.b=a; or a.b = [a]; or a.b = {'x':a};

    可选方案:
    1.var data={};b.push(a);a.setAttribute('GUID') = GUID;data[a.getAttribute('GUID')][b] = b;
     

结论:

  1. 只为DOM对象设置事件类型的属性值(注意避免准则1中的情形)
     
  2. 其他属性通过一个DOM对象的GUID进行关联,存储到一个独立的对象中去
     
  3. 由于做第二步操作会产生人为的内存浪费,所以,需要引入一个适当的垃圾清理机制对其进行清理

DOM对象泄漏测试用例:

<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<div id="x">X容器 ^_^</div>
<button id="y">重置容器X中的内容</button>
<script>
var md = function(module){
    if(!module){return;}
    var dbtn;
    var obtn = [];
    var ret = {
        init:function(){
            /*
            测试1,与DOM对象在同一作用域中申明function对象时
            如果该DOM对象为私有变量,则产生于作用域链中的隐性引用也将计为有效引用,会出现泄漏
            如果该DOM对象为共享对象,则因为每次会对该对象重新赋值,旧的引用自动去除,不会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.onclick = function(){};
            */
           
           
            /*
            测试2,只要函数定义不在DOM对象作用域,不会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.onclick = ret.show;
            */
           
           
            /*
            测试3,属性值内容与DOM对象间无引用,无论该DOM对象是共享对象还是私有变量,不会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = ret.data;
            */
           
           
            /*
            测试4,当属性值为显式的对自己的引用,无论DOM对象为私有变量还是共享对象,会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = dbtn;
            */
           
           
            /*
            测试5,将此DOM对象设置为另一对象的显式引用
            当属性值包含function类型时,无论DOM对象为私有变量还是共享对象,会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = ret.fndata;
            obtn.push(dbtn);
            */
           
           
            /*
            测试6,将此DOM对象设置为另一对象的显式引用
            当属性值为隐性的对自己的引用,不在同一作用域下进行的赋值,无论DOM对象为私有变量还是共享对象,不会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = ret.selfdata;
            obtn.push(dbtn);
            */
           
           
            /*
            测试7,将此DOM对象设置为另一对象的显式引用
            当属性值为某对象,而该对象又包含对该DOM对象的引用,无论DOM对象为私有变量还是共享对象,会出现泄漏
            */
            /*
            var dbtn = module.getElementsByTagName('button')[0];
            //dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = ret.cycledata;
            obtn.push(dbtn);
            */
           
           
            /*
            测试8,将此DOM对象设置为另一对象的显式引用
            当属性值不包含function类型时,且不存在对该DOM对象存在引用的对象,则不会出现泄漏
            */
            /*
            //var dbtn = module.getElementsByTagName('button')[0];
            dbtn = module.getElementsByTagName('button')[0];
            dbtn.data = ret.data;
            obtn.push(dbtn);
            */
        },
        show:function(){},
        fndata:{'data':function(){}},
        selfdata:{'dbtn':dbtn},
        cycledata:{'obtn':obtn},
        data:{q:[1,2], s:'string', i:100, b:true}
    };
    return ret;
};
var dx = document.getElementById('x');
var my = md(dx)

var dbtny = document.getElementById('y');
dbtny.onclick = function(){
    dx.innerHTML = '<button>new button '+Math.random()+'</button>';
    my.init();
};
</script>

避免DOM对象泄漏的测试用例:

<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<div id="x">X容器 ^_^</div>
<button id="y">重置容器X中的内容</button>
<script type="text/javascript">
var DNA = {
    pool:{},
    set:function(node, attr, value){
        var GUID = node.getAttribute('GUID');
        if(!GUID){
            GUID = 'GUID'+Math.random();
            node.setAttribute('GUID', GUID);
        }
        if(!this.pool[GUID]){
            this.pool[GUID] = {};
        }
        this.pool[GUID][attr] = value;
    },
    get:function(node, attr){
        var GUID = node.getAttribute('GUID');
        if(!GUID){return;}
        return this.pool[GUID][attr];
    }
};
var dx = document.getElementById('x');
var dbtny = document.getElementById('y');
var obtn = [];
var my = {
    init:function(){
        var dbtn = dx.getElementsByTagName('button')[0];
        obtn.push(dbtn);
        DNA.set(dbtn, 'data', dbtn);
        //DNA.set(dbtn, 'data', obtn);
        //dbtn.data = dbtn;
    }
};
dbtny.onclick = function(){
    dx.innerHTML = '<button>new button '+Math.random()+'</button>';
    my.init();
};
</script>

P.S. JQuery中防止内存泄漏需要确保JQuery不能被多次初始化 - -!

你可能感兴趣的:(Web,develop)