JavaScript极速狂飙:CSS样式表的渲染效率

meizz 2005-12-09 05:18:25

我的MzTreeView1.0树控件发布至今,得到了不少意见反馈,很多网友给了我很多的中肯的建议,也指出了这个控件里的诸多BUG和不足之处,所以我准备写一个新版本的树,将大家的建议都整合进来实现。这几天我就一直在写新版的树,树控件最重要的是效率,特别是大节点量的时候,效率稍微差点的模式就会拖垮浏览器,所以新版的树我首要的还是提高效率,比如增加异步数据加载的支持等,另外我还有一个设想,就是树的树型结构竖线用样式表(背景图)来实现,样式表背景图片只需要加载一次,而现在这个模式(用多个<img>)图片虽然有缓存机制,但还是有可以每张小图片都请求一次服务器的,所以我想用样式表来实现有多么的好呀,代码又精简,结构又清晰,效果又酷,但是结果我将近一个星期的测试,我这种设想彻底失败,原因就是样式表的渲染效率太差。新的构想没能实现,心情有些沮丧,但我想也应该让大家分享一下这个测试成果。

这里我再解释一下树型里的竖线,树的左边都有 ┌ ├ └ │ 这些竖线图表示树层次,我的1.0版里是用一张张的小图片堆积起来的,而这种使用样式表的是用<div class="l2"></div> 这种代码来实现的,样式表负责填充背景图。

#mtvroot div td{width:20px;height:20px;}
#mtvroot .l0{background:url(line0.gif) no-repeat center}
#mtvroot .l1{background:url(line1.gif) no-repeat center}
#mtvroot .l2{background:url(line2.gif) no-repeat center}
#mtvroot .l3{background:url(line3.gif) no-repeat center}
#mtvroot .l4{background:url(line4.gif) no-repeat center}
#mtvroot .ll{background:url(line5.gif) no-repeat center}
#mtvroot .pm0{background:url(plus0.gif) no-repeat center}
#mtvroot .pm1{background:url(plus1.gif) no-repeat center}
#mtvroot .pm2{background:url(plus2.gif) no-repeat center}
#mtvroot .pm3{background:url(plus3.gif) no-repeat center}
#mtvroot .expand .pm0{background:url(minus0.gif) no-repeat center}
#mtvroot .expand .pm1{background:url(minus1.gif) no-repeat center}
#mtvroot .expand .pm2{background:url(minus2.gif) no-repeat center}
#mtvroot .expand .pm3{background:url(minus3.gif) no-repeat center}

上面这段CSS是我在脚本里动态生成的一段样式的片段,我把它贴上来,有助于后面的讲解。运用样式表之后,果真精简了许多,每个节点的生成也够快,但我发现,当我的树节点量达到,比如说300-500个节点之后,节点生成的效率没有影响什么,但每个节点的展开/收缩很慢很慢,需要几秒钟以上甚至10秒,且这个期间的CPU占用率是100%。说明一下,树型的展开/收缩是设置父节点的 style.display = none|block 来实现的。我的电脑配置是:AMD2800+ 1GDDR400内存,配置不太差的。

我首先的反应是:是不是用了太多的<table>影响了效率?因为我每一个节点都用了一个<table>,但是我把<table>换成了<div>、<span>等,效率没有什么改善,说明这个CPU占用率100%的问题不是HTML标签的问题,那么剩下来的问题就是这里使用了样式表。

以一个500节点的量来说吧,1.0里左边大概要堆积2000个左右的小图片。这种情况在浏览器端设置本地不缓存的时候会存在很大的问题,要加载这些多的小图片需要消耗不少的时间和服务器资源,所以我才会有这种新的用样式表来解决的想法,现在换成样式表法,也就是大概有2000个地方需要用样式表来渲染出背景图。我测试了各种情况,再对比1.0版的代码得出的结论是:CPU的点用率如此之高,唯一的原因也就只有这种渲染的耗时了。验证也非常简单,我把上面的样式表的左边 #mtvroot 这部分去掉,也就是去掉样式表的依托关系,测试的结果发现效率改善了很多,但耗时依然是可观的,有3-5秒之多。

另外我换了不同的浏览器,测试的结果也不太一样,在IE里最为恶心,比如说我在某个节点有500子节点,我将它收起(CPU100%,等待3-5秒),也就是display="none",这时候若我去收起这个节点的父节点(这个节点没有其它的同级节点,即它的父节点只有它这么一个子节点),照理说只有一个节点,收起应该是即时的事,但结果不然,结果又是3-5秒的CPU100%,这个让我狂郁闷,也就是说即使HTML对象被display="none"隐藏掉了,但是对它的父级进行任何操作的时候,IE会对这些被隐藏的对象用样式表重新渲染一遍,真是搞不懂IE的开发者当初是怎么想的。

我又到FIREFOX里测试了一下,在收起的时候(display=none)是瞬间的,可以肯定,FF对待被隐藏的对象不会再消耗精力。当然展开的时候所有的浏览器都一样:3-5秒的CPU100%,不过FF稍微要快些。

通过上面的这些现象我得出这么一个结论:样式表在动态渲染的时候效率并不高;在父容器发现状态变化的时候会引起它的所以子孙对象的样式表重新渲染;FireFox 对待被display=none隐藏的对象不会重新渲染而IE会。

那么这种样式表的渲染效率问题以前为什么一直没有被发现呢?嘿嘿,大家做网页的时候难得会做到这种极端的时候,一个页面里有几千个需要样式表渲染背景图。通常也就几个地方或者几十个地方了,所以感觉不出来渲染的效率,也感觉不出这方面在不同的浏览器之间的差别。但是在做树这些的控件的时候必定会碰到各种极端的问题,比如大数据量的数组,生成的HTML对象的多少等等,象这种渲染的效率差别也只是我在写JS脚本时碰到的问题之一而已。今天我把这个测试结果共享出来是希望对大家以后写程序的时候有所借荐,在做设计的时候有所考虑。

最后多谢大家对我写的控件的肯定与支持,谢谢了!
meizz(梅花雪)
...全文
363 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
up
sxl6159078 2005-12-13
  • 打赏
  • 举报
回复
up
hbhbhbhbhb1021 2005-12-12
  • 打赏
  • 举报
回复
风之石的原来的那个CSS问题是
table-layout:fixed吧?托你的问题,我也赚到了。{-_+}

我的这里运行你的代码由于没有图片收根结点虽然有些慢,但是没挂。
我突然有个问题,在ORACLE等一些东西都是找不到东西会更慢,而这里找不到图片却变快了。???
pq000 2005-12-12
  • 打赏
  • 举报
回复
你们太牛了!……
gu1dai 2005-12-12
  • 打赏
  • 举报
回复
晕。
renyu732 2005-12-11
  • 打赏
  • 举报
回复
學習學習
GODProbe 2005-12-11
  • 打赏
  • 举报
回复
我做过一个3级树、前几天把它改造成为了4级、受梅花雪的树的启发也加入了页面搜索聚焦着色功能。
但是现在我的4级树节点量达到3千以上、初始显示和搜索聚焦的时间竟然要5、6秒!试问梅老大您制作树的时候都有些什么可优化效率的地方?还是只有您的开发手册里写的那些?(我脚本不是很熟、所以用的都是常规方法、每个节点都是DIV)

另外我觉得竖线多余、我的树全没有竖线、呵呵、不过我把BODY的底色设为#F8F8F8、这样所有的DIV边框都会显示为隐约的白线、当层层展开节点的时候左侧也会有符合层数的竖线、唯一缺点是竖线不是和图标对齐而是DIV的左边框、不知道这个思路有木有用、因为这样应该一点不耗资源。
dh20156 2005-12-10
  • 打赏
  • 举报
回复
一次收起1000个节点还好,大概1秒,收起根节点就挂了,郁闷啊。 -_-!!!
dh20156 2005-12-10
  • 打赏
  • 举报
回复
梅大,不知道用这种方式会不会有所改善,用ul和li,就是载入的时候慢,载入总共1万个节点后,感觉还是挺快的:

<!-- m1.gif是─,p1.gif是┼l1.gif是├ -->
<style>
.lo{list-style-image:url(m1.gif);}
.lc{list-style-image:url(p1.gif);}
.ll{list-style-image:url(l1.gif);}
a{color:black;text-decoration:none;}
a:active{color:highlighttext;background:highlight;}
</style>

<script language="javascript">
function changesub(obj){
if(obj.children[1] != null){
var oldflag = obj.children[1].style.display;
if(oldflag = null || oldflag == "none"){
var newflag = "block";
obj.className = "lo";
}else{
var newflag = "none";
obj.className = "lc";
}
obj.children[1].style.display = newflag;
}
}
function testTree(){

var tstr = "<LI class=\"lo\"><A href=\"javascript:;\" onclick=\"changesub(this.parentElement)\">Root</A><UL>";
var bstr = "</UL></LI>";

var sub3 = new Array();
var s = 0;
for(var c=0;c<10;c++){
sub3[s++] = "<LI class=\"ll\"><A href=\"javascript:;\" onclick=\"changesub(this.parentElement)\">Sub Sub Sub item"+c+"</A></LI>";
}
var sub3str = sub3.join('');

var sub2 = new Array();
var t = 0;
for(var b=0;b<10;b++){
sub2[t++] = "<LI class=\"lo\"><A href=\"javascript:;\" onclick=\"changesub(this.parentElement)\">Sub Sub item"+b+"</A><UL>"+sub3str+"</UL></LI>";
}
var sub2str = sub2.join('');

var sub1 = new Array();
var i = 0;
for(var a=0;a<20;a++){
sub1[i++] = "<LI class=\"lo\"><A href=\"javascript:;\" onclick=\"changesub(this.parentElement)\">Sub item"+i+"</A><UL>"+sub2str+"</UL></LI>";
}
var newstr = tstr + sub1.join('') + bstr;
document.write(newstr);
}
testTree();
</script>
dh20156 2005-12-09
  • 打赏
  • 举报
回复
梅大的钻研精神真是值得大家学习。
CSS确实头痛,用得好可以帮大忙,用不好会把人气的够呛。还记得偶原来提的一个问题么,大家一起研究了大半天,后来JK提供的一个CSS的属性很好的解决了问题。
学习!
BlueDestiny 2005-12-09
  • 打赏
  • 举报
回复
好贴,谢谢梅花兄了^_^
xtuwz 2005-12-09
  • 打赏
  • 举报
回复
呵,我可要學習學習
xjdawu 2005-12-09
  • 打赏
  • 举报
回复
*_* 不容易
dalisong 2005-12-09
  • 打赏
  • 举报
回复
hbhbhbhbhb1021 2005-12-09
  • 打赏
  • 举报
回复
板凳,嘿嘿,再顶,强烈支持
hbhbhbhbhb1021 2005-12-09
  • 打赏
  • 举报
回复
沙发,哈哈,顶

87,921

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧