jQuery EasyUI Datagrid效能優化專題
jQuery EasyUI的Datagrid元件功能算是很強大了,不過效能確實不怎麼樂觀,而對於效能問題,網路上幾乎也找不到相關的優化資料,所謂的牛人們可能都望而卻步了。本部落格以後會帶著分析Datagrid元件的效能問題,並且給出優化方案,也希望大家能集思廣益,給出一些好的想法。
慢在哪些方面
以目前對Datagrid的瞭解程度去看待效能問題,主要有以下幾點:
- 載入大資料量時比較慢(不考慮服務端返回資料的時間),這點尤其體現在IE瀏覽器裡面;
- 大資料量時,載入後,操作很不流暢,勾選慢,singleSelect為true的話點選也比較慢,IE瀏覽器也是尤其突出;
- 資料量一般,但是欄位特別多的話,載入和操作也比較慢,當然了,這種情況比較少見;
- 可編輯表格的效能則是更為糟糕,資料量達到幾十條的時候,操作就會相當不流暢,IE依舊很突出
大資料量的載入
原因分析
不考慮服務端返回資料的時間,在前臺獲取到大資料量後,往表格裡插入tr的時候,IE執行的效率非常低,2000條資料要45秒左右,其他瀏覽器則很快。
通過單步除錯發現,預設檢視在最後將tr寫到table裡面用的是jQuery的html()函式,就是這個函式在IE下執行效率非常低。
解決方案一:返璞歸真
jQuery是個很鋒利的工具,可有時候我們也得返璞歸真一下,為什麼非要用jQuery的html()函式呢,我們就用javascript dom物件裡面的innerHtml屬性不就可以了麼,而且換成innerHTML屬性方式的話,效率提高几十倍。
所以,大資料量載入慢的問題,就這麼簡單就解決了,修改預設檢視render方法最後那句:
- //1.3.3版本是這樣的,其它版本也是這句程式碼
- $(_1e0).html(_1e4.join(""));
改為:
- $(_1e0)[0].innerHTML = _1e4.join("");
注意:innerHTML雖然符合w3c標準,而且各個瀏覽器也都支援,但是表現出的行為卻又差異,另類的瀏覽器依舊是IE,主要表現在以下幾個方面:
- IE6,IE7,IE8瀏覽器設定innerHTML屬性會忽略html5屬性和標籤,搜尋關鍵詞"innerHTML IE html5";
- IE幾乎所有版本設定innerHTML屬性時都會把href,src屬性自動轉化為絕對路徑,搜尋關鍵詞"innerHTML IE href";
- IE幾乎所有版本的table相關標籤的innerHTML屬性是隻讀的(td除外),搜尋關鍵詞"innerHTML IE table;
幸運的是EasyUI的datagrid預設檢視沒有使用html5技術,呼叫innerHTML的節點也並非table節點(是div),而href,src等轉化為絕對路徑並沒有什麼影響。
解決方案二:使用scroll檢視
VirtualScrollView檢視官網已經寫出來了,不過有兩個Bug而已,我對這個檢視的原始碼也分析過,請大家參照:
http://www.easyui.info/archives/1404.html
勾選和點選
原因分析
勾選和點選(開啟singleSelect)慢的原因其實是一樣的,都是選擇器執行效率低,這裡我拿勾選的情況來分析。
具體的分析過程我就不描述了,知道用chrome,fireBug,IE開發者工具除錯的同學,應該都有定位問題的思路:先定位執行效率低的函式,再在函式內定位執行效率低的語句。
checkbox導致操作不流暢的原因,我最後定位到opts.finder.getTr這個方法上,我們來看它的程式碼片段:
- if (type == "checked") {
- return (_21d == 1 ? dc.body1 : dc.body2).find(">table>tbody>tr.datagrid-row:has(div.datagrid-cell-check input:checked)");
- }
這段程式碼是獲取已經被勾選的rows,大家可以看到,這是純粹的jQuery選擇器查詢,效率就慢在has這個偽選擇器上,它是針對所有後代元素的,查詢的效率是比較慢的,又是在這麼多資料量的情況下,其效果就可想而知了。
優化方案一:選擇器優化
其實對於checkbox列的DOM結構是固定的,我們完全可以用速度快的選擇器來代替":has",我們先直接用路徑選擇器找到"input:checked",然後使用三次parent()函式返回tr,寫法雖然複雜了,但是效率應該提高一點,所以我們改成這樣:
- if (type == "checked") {
- return (_21d == 1 ? dc.body1 : dc.body2).find(">table>tbody>tr.datagrid-row>td>div.datagrid-cell-check>input:checked").parent().parent().parent();
- }
我用自己的服務大概測試了修改前後的效率(jQuery版本1.8.0,EasyUI版本1.3.3,singleSelect為false,2000條資料勾選一條記錄的測試情況):
瀏覽器 | 執行時間 | 瀏覽器 | 執行時間 | |
---|---|---|---|---|
原版 | IE9 | 600ms | chrome | 60ms |
選擇器優化 | IE9 | 560ms | chrome | 60ms |
從上面的結果可以看出,在這種測試條件下,我們提高的效率並不大,IE9下提高的效率儘管有所提高,但是還是很不理想,而chrome下效能基本一樣。測試過程中發現,如果使用jQuery2.0的話,IE9下的執行時間將達到45000ms,幾乎讓人奔潰,看來儘管IE9勉強支援jQuery2.x,但是效率很挫。
優化方案二:實時記錄優化法
既然慢在DOM結構巨大時,jQuery選擇器的搜尋效率不是很好(特別是在IE下)。如果我們每次操作都記錄下勾選的tr,那麼就完全可以繞開選擇器。
具體該怎麼做呢,我們給$.data(target,'datagrid')變數增加兩個屬性:"checkedTrsBody1"和"checkedTrsBody2"分別儲存frozen部分和normal部分被勾選tr的引用,然後在各個設計到勾選的操作中維護這兩個屬性。最後,獲取被勾選tr的時候就可以直接從這兩個屬性中取了,其耗時是可以忽略的。
那麼究竟哪些操作會影響到被勾選的tr呢,我們羅列一下,也就以下幾種:"checkRow","uncheckRow","uncheckAll","checkAll","deleteRow","loadData","load","reload".我們只要在這些介面中維護起"checkedTrsBody1"和"checkedTrsBody2"屬性就可以了。
至於具體的程式碼怎麼改,我就不貼了,最好就直接改動原始碼了,思路很清晰,請各位自己去實現,是在理不出頭緒的,請參照我的實現:
http://www.easyui.info/version/jquery-easyui-1.3.3/plugins/jquery.datagrid.js
資料報表統計
勾選效能測試【IE9;jQuery-1.8.0;EasyUI-1.3.3;singleSelect:false】:
優化執行時間(ms) | 原版執行時間(ms) | |
---|---|---|
200條 | 7 | 64 |
500條 | 20 | 160 |
1000條 | 27 | 308 |
2000條 | 53 | 623 |
4000條 | 107 | 1323 |
6000條 | 192 | 2072 |
8000條 | 265 | 2865 |
10000條 | 331 | 3611 |
可以看出來,無論是在IE9下,勾選效率都提高了很多倍(chrome下效率也有顯著提高)。開啟singleSelect的優化思路是一樣的,所以不寫重複文字了。
渲染效能測試【IE9;不考慮伺服器響應時間】:
優化渲染時間(ms) | 原版渲染時間(ms) | |
---|---|---|
200條 | 49 | 326 |
500條 | 122 | 1821 |
1000條 | 253 | 7002 |
2000條 | 525 | 27320 |
4000條 | 1083 | 110115 |
6000條 | 1683 | 200000 |
8000條 | 2261 | 200000 |
10000條 | 2900 | 200000 |
原版的datagrig,我本地的測試環境資料在4000條以上時,IE9基本就卡死了(可能機器效能不太好),無統計價值了,即便是4000條資料,也要將近2分鐘才渲染完,顯然沒人能夠忍受。
從報表很明顯可以看出優化過的表格,即便是10000條資料,3秒也就渲染完成了。
優化演示
未優化版本:http://www.easyui.info/version/jquery-easyui-1.3.3/demo/datagrid/bigdata_checkbox.html
優化版本:http://www.easyui.info/version/jquery-easyui-1.3.3/demo/datagrid/bigdata_checkbox_optimized.html
*******轉載:http://www.easyui.info/archives/1435.html