我的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腳本時碰到的問題之一而已。今天我把這個測試結果分享出來是希望對大家以後寫程式的時候有所借薦,在做設計的時候有所考慮。
最後多謝大家對我寫的控制的肯定與支持,謝謝了!