现在的位置: 首页 > easyui > Grid > datagrid > 正文
jQuery EasyUI Datagrid性能优化专题
2013年08月15日 datagrid ⁄ 共 3613字 评论数 39 ⁄ 被围观 63,890 views+
文章目录
[隐藏]

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. //1.3.3版本是这样的,其它版本也是这句代码
  2. $(_1e0).html(_1e4.join(""));

改为:

  1. $(_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这个方法上,我们来看它的代码片段:

  1. if (type == "checked") {
  2.     return (_21d == 1 ? dc.body1 : dc.body2).find(">table>tbody>tr.datagrid-row:has(div.datagrid-cell-check input:checked)");
  3. }

这段代码是获取已经被勾选的rows,大家可以看到,这是纯粹的jQuery选择器查询,效率就慢在has这个伪选择器上,它是针对所有后代元素的,查找的效率是比较慢的,又是在这么多数据量的情况下,其效果就可想而知了。

优化方案一:选择器优化

其实对于checkbox列的DOM结构是固定的,我们完全可以用速度快的选择器来代替":has",我们先直接用路径选择器找到"input:checked",然后使用三次parent()函数返回tr,写法虽然复杂了,但是效率应该提高一点,所以我们改成这样:

  1. if (type == "checked") {
  2.     return (_21d == 1 ? dc.body1 : dc.body2).find(">table>tbody>tr.datagrid-row>td>div.datagrid-cell-check>input:checked").parent().parent().parent();
  3. }

我用自己的服务大概测试了修改前后的效率(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

目前有 39 条留言 其中:访客:23 条, 博主:12 条 引用: 4

  1. 小时候我可狠了 : 2013年09月01日00:41:25  -49楼 @回复 回复

    我想问下 jQuery EasyUI Datagrid这个能随浏览器大小改变大小吗 尤其是有了data-options=”frozen:true”这个属性的时候


    • 管理员
      世纪之光 : 2013年09月01日09:46:46  地下1层 @回复 回复

      随浏览器大小改变的话,一般是结合layout使用,设置他们的fit为true。另外easyui没有frozen这个属性。

      • 小时候我可狠了 : 2013年09月01日15:07:35  地下2层 @回复 回复

        大体功能到是能实现,刷新浏览器的时候就自动适应了 可是用鼠标改变浏览器的大小 datagrid还是不跟着变的


        • 管理员
          世纪之光 : 2013年09月02日09:13:56  地下3层 @回复 回复

          fit设置为true的话,只是告诉datagrid,要随着随时随地填充满整个父级元素,所以你鼠标拖动浏览器,datagrid是否能自适应,不光是fit决定的,还要看你的父元素。前面已经说过了,结合layout使用可以实现,或者父元素使用百分比,而且是相对于Body的百分比。

          • hua7831 : 2014年06月24日15:47:50  地下4层 @回复 回复

            设置html,body{width:100%; height:100%}

  2. 鱼腩 : 2013年09月11日16:09:25  -48楼 @回复 回复

    小雪,我在优化了datagrid的$(_1e0).html(_1e4.join(“”)); 类似语句之后,速度快了,但是我发现在表格数据到3000条的ie9浏览器上,鼠标在行数据上移动的时候有延迟和闪烁的情况,ie8只有延时;之后数据越多越严重,在火狐上没有这个问题,这个会是选择器的问题吗。

  3. aylx : 2013年09月23日15:40:06  -47楼 @回复 回复

    太牛了,由衷的佩服。虽然文章里写的整个优化过程思路很直接很干脆的样子,但是楼主背后也是付出了很多汗水的吧。以后我多到这里学习


    • 管理员
      世纪之光 : 2013年09月23日15:57:59  地下1层 @回复 回复

      性能问题一般都是要付出很多才能有所改进的,我都是通过反复调试,查找资料,然后总结修改的。

  4. m1k : 2013年09月24日16:01:28  -46楼 @回复 回复

    我现在做到一个项目,某页一个datagrid是不分页的,然后做了每分钟的定时刷新。
    datagrid在初始化的时候,需要把远程数据加载完毕后,对数据进行分析,然后列 formatter 和 style设置,几乎每列都有(包括图片、颜色和数值变化分支),最后在loadSuccess的时候,还要把某列相同的进行合并操作,总之用了很多的循环和判断分支,
    现在才70多条记录,效率感觉都稍微有点慢了。
    每次定时刷新的时候,数据加载都要卡顿一下,然后数据加载完毕后,需要合并的那列会“跳”一下然后才会合并,有没有什么办法进行优化?
    之前上面写的优化方面我都用到了,没有多大的改善,如果我不分页的话,会不会从渲染上得到性能的提高?


    • 管理员
      世纪之光 : 2013年09月24日16:17:23  地下1层 @回复 回复

      你这个问题似乎很复杂,可能我的回答要让你失望了,一方面我没有你环境,没有时间去重现你的问题,即便是问题重现了,我可能也未必分析出原因来。
      如果你能用html+json来重现问题的话,建议到www.yibeizi.us写个详细的帖子和demo。可能需要优化的地方可能很多。

  5. aylx : 2013年10月30日17:01:11  -45楼 @回复 回复

    大数据量的加载-优化方案一,请问默认视图的render方法是在哪里定义的呢?我这边看了jquery-easyui-1.3.3的jquery.easyui.min.js,里面没找到类似的代码:$(_1e0).html(_1e4.join(“”));
    找到了一句类似的$(_6a0).html(_6a4.join(“”)),但是不确定这个是不是默认视图的render方法,改了以后也没什么效果

    • opacity:0 : 2015年04月23日16:07:10  地下1层 @回复 回复

      $(_1e0).html(_1e4.join(“”));这段代码在jquery-easyui-1.3.3/plugins/jquery.datagrid.js里

  6. skylinger : 2013年11月04日15:43:27  -44楼 @回复 回复

    1.3.2版本怎么优化?没找到这句啊“$(_1e0).html(_1e4.join(“”)); ”

    • hh7vv : 2015年11月18日17:20:02  地下1层 @回复 回复

      搜索 _5f5.push(“”);

  7. 逍遥不羁 : 2013年11月19日10:05:35  -43楼 @回复 回复

    非常感谢!受益颇多。刚好遇到IE下大数据量时加载慢的问题!很想请教,文中提到定位效率低的函数,再定位效率低的代码,如何操作?不胜感激!

  8. 风声云起 : 2014年01月08日16:13:21  -42楼 @回复 回复

    请问楼主,这个列表的checkbox,是可以进行单选和多选设置的,但是单选的时候并不是radio,很容易给人误解,怎么能改成radio的呢?


    • 管理员
      世纪之光 : 2014年01月09日22:57:46  地下1层 @回复 回复

      改肯定是可以改的,不过比较麻烦,涉及面比较广,找时间整理一下才能动手改,而且基本肯定要改源码。

      • 风声云起 : 2014年01月10日10:11:00  地下2层 @回复 回复

        嗯,感觉很麻烦

  9. yfan : 2014年03月11日16:38:52  -41楼 @回复 回复

    请教楼主 , 我的easyui是1.3.2 版本的。
    jsp页面加载的时候,刚开始的时候easyui的样式加载不出来,需要等一会才能出现,这个是什么原因?


    • 管理员
      世纪之光 : 2014年03月12日13:12:15  地下1层 @回复 回复

      JSP页面加载的时候首先是服务端要处理JSP的相关标签,然后是HTML,脚本的加载等。如果JSP处理的慢,或者DOM很臃肿的话,document.ready的触发执行是很靠后的,easyui的所有逻辑都是在document.ready之后才执行的。

      • yfan : 2014年03月12日14:37:28  地下2层 @回复 回复

        能够把这个顺序提前吗

  10. 我是程序员 : 2014年08月11日16:15:15  -40楼 @回复 回复

    :mrgreen: 感谢分享

  11. 漂泊 : 2014年11月28日10:58:55  -39楼 @回复 回复

    先给楼主一个赞,把优化做到这样确实不容易了。
    现在还有个问题请教,我们业务上经常需要用到大范围的表格编辑功能,数据行数差不多在四五十条,但是列数也有可能在四五十个左右,这种大范围的编辑十分的效率低下,问下有没有可以优化的方案?


    • 管理员
      世纪之光 : 2014年12月01日13:20:33  地下1层 @回复 回复

      这种情况之前听人反馈过效率低下,个人没有亲自测试过,字段太多,同时又有几十条数据处于可编辑状态。算是40个字段,40条数据,假设都处于可编辑状态,那么因此而产生的表单(同时还可能产生额外的panel,比如combobox编辑器)也就有40×40 = 1600个,要做到高性能确实不容易,有时间的话好好研究研究。

    • Kevin.Guo : 2014年12月26日19:00:20  地下1层 @回复 回复

      我们项目也这样用了,应该复杂程度挺高,没有感觉效率多低下

  12. : 2015年03月04日14:46:35  -38楼 @回复 回复

    有50个列加载就很慢,有优化方案吗?


    • 管理员
      世纪之光 : 2015年03月05日12:39:21  地下1层 @回复 回复

      因为列过多而引起的性能问题 暂时还没有做分析,比较抱歉了,有结论的时候,会更新这篇文章的。

  13. 冷雪花 : 2015年06月30日16:05:06  -37楼 @回复 回复

    非常感谢 性能提高了一点 😛

  14. : 2015年08月04日15:09:55  -36楼 @回复 回复

    1.4.2版本怎么优化datagrid加载效率


    • 管理员
      世纪之光 : 2015年08月06日10:23:07  地下1层 @回复 回复

      本文只提供优化思路,并不为每个版本的easyui做优化,谢谢。

  15. 有良心的搬运工 : 2016年02月19日14:44:08  -35楼 @回复 回复

    大神您好,用了你的优化方法之后感觉速度提升了至少一半以上,我是一名初级程序猿,想请教你一个问题:
    关于这篇文章里,我用到了你改的jquery.datagrid.js 这个js。
    现在问题是我用1.4.1的easyui,其中如果使用了textbox类型的文本框,整个grid就不好用了,无法编辑,在代码2552行 data.length属性不存在。
    在这个js是easyui的标配js吗,在网上能找到吗? 有什么解决办法吗? 😥


    • 管理员
      世纪之光 : 2016年03月19日15:31:23  地下1层 @回复 回复

      我的修改只是提供一个思路,没有办法兼容所有版本

      • 林雉 : 2016年09月05日17:00:14  地下2层 @回复 回复

        一个datagrid通过 onSelect选择一行加载出另一个datagrid,另一个datagrid的数据弹出框提示docelltip只提示一次.怎么解决让另一个datagrid的docelltip一直起作用 😳 😳 😳

给我留言

留言无头像?


×