`
Relucent
  • 浏览: 207168 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

带选择框的JS树控件2 (为JSTree再次提速)

    博客分类:
  • JS
阅读更多

以前写过一个带选择框的JS树控件
但是当时发现一个问题,第一次选中根节点会明显感觉卡一下。
那是因为子节点的数据还没有生成,选中根节点的话需要初始化全部数据。(那个tree有5000个节点)


于是我思考一个问题,如何让多节点树的页面达到更快的效率

经过测试发现,JSTree的主要效率瓶颈在两个地方。
1.页面HTMLElement的创建
2.树子节点的检索


页面创建一个HTMLElement是很耗时的,无论使用createElement或者是是innerHTML都一样。
而且这一步只能一个节点一个节点慢慢地生成,虽然可以通过减小单个节点的HTML元素量的方法提高一些速度,但是对于对于上千个节点来说仍然需要等上几十秒。
(1个节点如果有5个HTMLElement,生成1000个节点大概3秒左右)

所以只有通过异步展示的方法来进一步减少一次生成的节点数。
页面加载时并不立即生成所有节点的HTML元素,而是用户展开多少节点就生成多少节点,节点的生成发生在用户展开这个节点的时候。 这样减少了每次生成的节点数,消除了使用者的等待时间。

而对于节点的检索,这和数据的组织方式有关。
一般的组织方式是使用数组。(解析XML的话太慢,不考虑。只考虑使用json的情况)
但是在数组中检索一个节点的效率实在不敢恭维,如果节点是N个,那么全部节点数据组装起来的效率就是N*N
在节点少的时候不明显,但是如果有1000个节点,那么明显会发觉延迟了10多秒。延迟速度按指数增加。

MzTree(梅花雪)使用了另外一种方式,他没有使用数组而是使用一个简单对象来存放数组。
并且用一个字符串存放节点的索引关系(将所有的节点名(即类的属性名)join()成一个大字符串)
当需要获得子节点的时候使用正则匹配一步获得子节点ID,从而获得子节点。
经过测试发现,使用正则匹配的算法检索节点效率比使用for循环要高出很多。

这个效率已经满足一般大数据jstree的需要。
(具体算法,去参考MzTree梅花雪)



对于一般的Tree可以通过异步初始化节点数据(不是初始化节点HTML)的方法来解决延迟。
但是如果是checkbox-tree(带选择框的树),却不能使用这个方法。因为对于带选择框的JS树,选中根节点的话,子节点应给也被选中。所以选中根节点,子节点必须存在。 所以节点数据需要一次生成。

但问题是即使使用正则匹配的算法提高了效率,仍然会需要一段初始化的时间。
5000个节点数据全部初始化 使用for需要20-30秒,使用正则匹配算法需要6秒

那么有没有办法进一步提高效率呢?
按照一般Tree的做法初始化一个节点数据需要初始化这个节点的子节点数据,那么也就需要检索节点的子节点数据。(有点绕口)
这个检索子节点数据看来是比较耗费时间的,而且没有更好的提高检索效率的方法。
既然检索没有办法提速,那么有没有不使用检索获得子节点的方法呢?

答案当然是有的,只要我们更改传递过去的数据结构问题迎刃而解。

于是我们直接传递一个拼装好的树结构JSON(节点包含了子节点的数据,子节点的数据中又包含了子子节点的数据....)

数据结构如下:
{
id : 0
childrean : [
  {
   id : 01
   childrean : [
    {
     id : 011
     childrean : [...]
    },
    {
     id : 012
     childrean : [...]
    }
   ]
  }
  ,
  {
   id : 02
   childrean : []
  }
]
}

对于这种结构,页面的Tree可以直接使用而无需解析,免去了子节点的检索所耗费的时间,JsTree展示速度大大提高。
一个5000节点的树,节点数据全部初始化只需要500毫秒。


(其实还有一个优点,使用这种结构的数据JSTree容易扩充,稍作修改就可以改成支持数据异步加载的Ajax-Tree) 


 
 
PS:附件中是一个演示例子,虽然不是最终版本但是可以说明问题。

 

china_2.js 和 china_2_code.js 是节点数据(UTF-8编码)

 

 

参数说明

text        显示节点内容(必须)
id           节点id
checked 选择框选中状态 0 1 2

children 子节点数据

 

创建一个新节点的方法 new TreeNode( {} );

 

 

新建节点可能存在一些问题(单选框选中等问题),节点有checked属性的情况才会出现选择框。

 

 

 

 

 

 

感谢winner720发现的一个BUG

这部分代码要改一下(粗体部分)  TreePanel_0.5.rar

//瀑布(遍历所有子节点)
cascade : function(fn, scope, args){
  if(fn.call(scope || this, (args==null?this:args)) !== false){
    var cs = this.childNodes;
    for(var i = 0, len = cs.length; i < len; i++) {
      cs[i].cascade(fn, scope, args);
    }
  }
},

(以前是 args||this,当节点checked是0的时候可能出现返回this,虽然不影响展示结果,但是会造成一定泄露。改成(args==null?this:args)就不会出现问题了)

 

 

modify:
TreePanel_test_0.x  测试演示版本
TreePanel_all.rar      完整演示版本
TreePanel_0.5.rar    修正了一个内存泄露BUG
TreePanel_2.2.zip    增加了节点全部展开和全部折叠的方法,修正了节点显示时多余的竖线

TreePanel_2.3.zip    修复节点删除时多余的竖线

 

备注:附件请下载最新的版本。 (旧的的版本可能存在未修改BUG,没删除只是为了留作做为备份)

 

这个树最初设计目的快速展示一颗带选择框静态树,虽然也提供了节点增加以及删除等功能,但这些没有经过仔细测试,且不是它的长项。

  • 大小: 28.7 KB
分享到:
评论
51 楼 wanghaosvse 2012-07-03  
请问楼主,有没有跟数据库同步的动态加载
50 楼 ultime 2012-05-31  
cqhydz 写道
问一下动态加载如何修改呢,我发现没有展开事件,只有一个点击事件呢。

你下的版本比较低
49 楼 cqhydz 2012-05-29  
问一下动态加载如何修改呢,我发现没有展开事件,只有一个点击事件呢。
48 楼 ultime 2012-05-08  
ultime 写道
怎样改才能在选中父节点时,不是指中国而是指下面的省或市的时候不选中他下面的子节点。

或者说删除节点的时候怎样能删除该接点以下的子节点不删除当前接点。
47 楼 ultime 2012-05-08  
怎样改才能在选中父节点时,不是指中国而是指下面的省或市的时候不选中他下面的子节点。
46 楼 coolsky99ls 2012-04-24  
coolsky99ls 写道
发现一个问题,就是当数据量很大时,全选后进行提交,有时候会漏掉一些数据,而且漏掉的数据都是随机的,不知道是什么原因

这个东西我找到原因了,由于我数据太多,parseInt(Math.random()*10000)可能会出现重复,我又在后面加了一个


return ('_' + (new Date().getTime()) + '_' + parseInt(Math.random()*10000)+ '_' + parseInt(Math.random()*10000));
45 楼 coolsky99ls 2012-04-24  
发现一个问题,就是当数据量很大时,全选后进行提交,有时候会漏掉一些数据,而且漏掉的数据都是随机的,不知道是什么原因
44 楼 nabnabnab 2010-07-23  
确实全部展开非常慢
然后以后再点击任何东西 就卡死了
43 楼 cutesource 2010-07-20  
<p>大家引入各种框架的时候一定要注意是否引入内存泄露的隐患,关于js内存泄露可以参见这么一篇博文:</p>
<h1 class="title_txt"><span style="font-size: medium;"><a href="http://blog.csdn.net/cutesource/archive/2009/09/13/4549105.aspx">浏览器内存泄漏问题的跟踪与解决</a></span></h1>
42 楼 InnocentBoy 2010-07-20  
作者这个是不是很早的梅花雪树?
41 楼 Relucent 2010-07-14  
yinsha1988822 写道
全部展开速度慢。。。ie6表现明显。


全展开的话,无论什么JS Tree都很慢(HTMLElement加载显示很耗时)。

IE6至少要10秒吧。
40 楼 Relucent 2010-07-14  
shiren1118 写道
有一个问题想请教一下,用jquery的load()可以加载你这个树吗?貌似dtree,和梅花雪的都不可以,不知何故,还请指教


不行,机制不一样。
(jquery.load是异步将网页加载到HTMLElement中和这个(dtree/梅花雪)没什么关系。)
39 楼 shiren1118 2010-07-14  
有一个问题想请教一下,用jquery的load()可以加载你这个树吗?貌似dtree,和梅花雪的都不可以,不知何故,还请指教
38 楼 yinsha1988822 2010-07-12  
全部展开速度慢。。。ie6表现明显。
37 楼 haoljp 2010-07-07  
如果楼主能改成ajax方式加载子节点就比较完美了
36 楼 haoljp 2010-07-07  
请问楼当加载的时候我全部设置为未选中状态
之后我想设置id在["001","001001","001001001"]中的节点为选中状态,要怎眼设置呢
35 楼 lqixv 2010-06-17  
好东西总会对人有帮助的。
34 楼 Relucent 2010-05-24  
gecbzsyj 写道
1、最上级:中国,没办法收缩,
2、htm中只能引用china_2_code.js,引用china_2.js会提示JS错误(IE6)
3、建议可以设置参数,比如:自动选择子节点(只选中国,不跟选子节点),自动选择父节点(同个父节点下的子节点全选时,不自动选择父节点)。

以上希望楼主可以完善



china_2_code.js 的数据格式是经过转码的,对浏览器支持较好,但是相对大了很多。
china_2.js是未转码前的格式,方便看。
33 楼 Relucent 2010-05-24  
langshao 写道
很好的控件,正是我要找的——关键是出来以及选中的速度.

有一点不明白:china_2.js中的pid,是不是多余的?



呵呵,很久的东东了,还有人关注啊。
因为那个JSON数据是工具生成的,所以节点的无关字段也生成出来了。那个pid是多余的对显示树没有用处。
32 楼 lqixv 2010-05-21  
很好,特来表示感谢!

相关推荐

Global site tag (gtag.js) - Google Analytics