关于JS DOM创建大量数据 和 JS树 的优化

在公司有一个需求

优化视频播放器

 

播放器菜单是由JS 动态创建,有大量的Dom 创建操作

由于之前没有考虑到这种大数据量的情况下,在1000条数据 甚至连IE8都没有办法正常使用。

有两个菜单一个是

table 全列表,将所有的数据全部展现

一个是树形菜单,有分级(理论上无限级)

 

1. 不要使用 $("<tr></tr>").append($("<td></td>")) 或者 document.CreatElement("A") 这种方式

在大量的拼接之下,效率还是innerHTML 来的更高

http://www.cnblogs.com/jazzka702/archive/2009/05/23/1487789.html

http://hi.baidu.com/xu4820811cs/blog/item/365010ae705f62f3fbed50c8.html

网上已经有很多对比,这里就不赘述了。

 

当然 不能用 div.innerHTML += ""; 如果这样。 还不如CreatElement

通过字符串拼接 将所有的你想要的 HTML 拼接完成后,统一 innerHTML 创建.

 

2.说到字符串拼接,吐槽的点又来了。

你在网上搜索 往往都推荐你用数组拼接字符串,说速度要快一点 var arr = []; arr.push(""); arr.join('');

其实不然。

IE7,8  数组拼接 和 string+string 其实速度差异不大

IE9,ff,google,opera 下 string+string 都明显强于 arr

说穿了 还是为了照顾IE6

同样的拼接字符串 在IE6下。 数组还过得去, string+string 直接假死半天

 

3.尽量使用大容器控制事件

在之前的代码中 在使用$("<tr></tr>")创建的同时,同时绑定了事件。

其实在大量数据情况下,这也是不小的消耗。

比如

a text A  A  
a text A  A  
a text A  A  
a text A  A  
a text A  A  

 我要在第一列和第三列的A标签 加事件

 那么就应该在整个Table上面Click 事件

 而不是在创建的时候给每一个A标签加上事件.

 table 的 click的事件捕捉到后判断是否是A标签。 然后去做相应事件。

当然这种做法 还是有他的缺点。 不方面传值。 往往只能通过A标签 TR TD 上的属性来传值

 

4.SetTimeOut 异步输出。

其实在做完上面3的工作之后,除了IE6 已经完全是秒开了。

但是IE6还是有明显的卡顿。

SetTimeOut(function() = aaa

{

  //详细输出代码

  SetTimeOut(aaa,time)

},time);

判断好一次最大输出值,输出多少次。

这样的效果非常好。 在固定的一屏宽高下。 比如你一次输出100行正好可以铺满。

用户甚至感觉不到延时。

 

做完上面4部 在2000行 在IE6下面也毫无压力。

可惜在测试部传来噩耗。

我发现我忽略了一个问题。

在大量分组下,不太好使用SetTimeOut。而且遍历树的时候消耗极大

1.因为分组很琐碎,无法像整个输出一样 分割来输出(ps:其实这个都很好办,硬输出IE6 还是吃的下,在实在不行的情况下 还是可以SetTimeOut 分组输出)

2.遍历树 问题来了

{

  { id:1,pid:0}

  { id:2,pid:1}

  { id:3,pid:2}

  { id:4,pid:3}

}

类似于这样的数据(理论上是无限层)

原来的方法,也就是最正统的方法。

递归遍历

先遍历PID=0
然后再通过结果一层一层的继续遍历。 在层数深且多的情况下。IE6直接 禁止脚本。

 

想到了两种办法。

1. 采用101010101 这种方式。

ID自带节点信息。可以顺序遍历 我可以一次遍历就可以输出树

但是直接被boss pass掉。。 难道重新做数据库啊

当然这种写法也有他的问题

  (1)首先不好支持无限层

  (2)当移动节点的时候。 恶心事儿就来了

 

2.JS端 重新整理

换句话说 当Json 格式数据传到客户端后。

通过1-2次遍历重新整理为我想要的格式

{

  { id:1,pid:0,child:{

    {id:2,pid:1}

  }}

}

 

 1 var newGroup = {};
 2 var errerGroup = {};
 3 function Deep(json)
 4 {
 5       var arr,g;
 6       for(var i in json)
 7       {
 8         g = json[i];
 9       arr = FindNodes(g);
      SetNodes(g,arr);
10 } 11 } 12 13 function FindNodes(g,arr) 14 { 15 if(!arr) arr = []; 16 if(g.pid == 0){ //*分类 17 return arr; 18 } 19 else { 20 var pGroup = newGroup[g.pid]; 21 if(!pGroup) { 22 errerGroup[g.pid] = g; 23 return; 24 } 25 else { 26 arr.push(g.pid); 27 return FindNodes(pGroup,arr); 28 } 29 } 30 } 31 32 function SetNodes(g,arr) 33 { 34 if(!arr || arr.length == 0) 35 { 36 return newGroup[g.id] = g; 37 } 38 else 39 { 40 var tmpGroup = newGroup; 41 for(var i in arr) 42 { 43 tmpGroup = tmpGroup[arr[i]]; 44 } 45 tmpGroup[g.id] = g; 46 newGroup[g.id] = { pid:g.pid }; 47 } 48 }

 

 

这样newGroup 却是可以得到我想要的分组信息

但是有2个问题

1. 这样的写法 会改变原来的 json

当你得到 新的Json 的时候

你会发现 你传入的Json 已经被改变.

如果是克隆一份 (PS: 还没有测试), 但是确实担心 克隆一份 在大量分组下 性能损失严重

这个只有再测试了。

 

2. 子节点不能先于父节点出现

当然 如果你是走正常添加,ID顺序的话 确实没有问题;

所以我添加了一个 errerGroup 来存放找不到父节点,或者父节点后于子节点出现的情况

 

 PS: 家里vs 出问题了。 上面代码记事本纯手写也没有测试过.

 

补上测试后的代码

FinishingTree = { 
    newGroup: {},
    errorGroup: {},
    pidTag: "pid",
    indexTag: "id",
    tmpGroup: {},
    Deep: function(json) {
        var arr, g;
        for (var i in json) {
            g = json[i];
            arr = this.FindNodes(g);
            if (arr == -1) continue;
            this.SetNodes(g, arr);
        }
    },
    FindNodes: function(g, arr) {
        if (!arr) arr = [];
        if (g[this.pidTag] == 0) { //*分类
            return arr;
        }
        else {
            var pGroup = this.tmpGroup[g[this.pidTag]];
            if (!pGroup) {
                this.errorGroup[g[this.pidTag]] = g;
                return -1;
            }
            else {
                arr.push(g[this.pidTag]);
                return this.FindNodes(pGroup, arr);
            }
        }
    },
    SetNodes: function(g, arr) {
        if (!arr || arr.length == 0) {
            this.newGroup[g[this.indexTag]] = g;
        }
        else {
            var tmpGroup = this.newGroup;
            for (var i = arr.length - 1; i >= 0; i--) {
                tmpGroup = tmpGroup[arr[i]];
            }
            tmpGroup[g.id] = g;
        }
        this.tmpGroup[g.id] = { pid: g[this.pidTag] };
    },
    GetNewGroup: function(json, strPID, strIndex) {
        if (strPID) this.pidTag = strPID;
        if (strIndex) this.indexTag = strIndex;
        var tmpArr = [];
        tmpArr.push(json);
        var back = tmpArr.slice(0);
        this.Deep(back[0]);
        delete back;
        this.tmpGroup = {};
        return this.newGroup;
    }
}

 IE6下 4毫秒的样子

 

关于JS DOM创建大量数据 和 JS树 的优化

就是这样

 PS. 最后让我纠结的是。后来我才发现性能问题的源头 tm 不是在这里

 

 

转载于:https://www.cnblogs.com/CallMeTommy/archive/2012/06/12/2545736.html