找回密码
 立即注册

QQ登录

只需一步,快速开始

Crystal.Li 讲师达人认证 悬赏达人认证
论坛元老   /  发表于:2021-8-16 12:24  /   查看:4996  /  回复:10
本帖最后由 Crystal.Li 于 2021-8-16 14:27 编辑

在报表设计过程有时候会遇到大数据量的报表展示,那么对于大数据量的报表展示,如果一次性把所有数据加载到页面上,那势必会造成页面卡顿、反应慢等性能问题。那么对于这种大数据量的报表展示我们如何该做性能优化呢?

一、问题背景

前端性能优化一直是一个比较大的话题,实际项目中可能会遇到很多关于性能的问题,常见的优化手法也很多,比如合并JS/CSS文件、减少http请求、懒加载、图片压缩等。在这里我们只聚焦于当数据量比较大的时候,我们该如何去做性能优化。假如后端的小哥哥小姐姐们将几万条数据丢给前端,我们拿到之后该怎么做呢?其实核心思想就是分段去展示数据!每次只加载可视区域的报表数据,当翻到下一页时再取下一页的数据进行展示。这样每次报表渲染的时候,只会渲染当页可见的dom元素,不会一次性把几万行报表数据渲染加载到页面上。


二、优化实战
那么落到实际该怎么做呢?这里我就以ActiveReports JS纯前端报表控件为例,来看一下在AR JS中如何展示大数据量报表。
1、自定义报表翻页按钮
分页加载报表数据,首先要自定义翻页按钮,当点击到下一页时,再去加载下一页的数据。ARJS提供了自定义翻页按钮的功能,所以这里先添加自定义按钮:
  1. const prevPageButton = {
  2.       key: '$prevPageButton',
  3.       text: "上一页",
  4.       title: "prevPageButton",
  5.       enabled: true,
  6.       action: function () {}
  7. };
  8. const nextPageButton = {
  9.       key: '$nextPageButton',
  10.       text: "下一页",
  11.       title: "nextPageButton",
  12.       enabled: true,
  13.       action: function () {}
  14. };
  15. const pageCount = {
  16.       key: '$pageCount',
  17.       text: `1/ ${totalPage}`,
  18.       title: "pageCount",
  19.       enabled: true
  20. };
复制代码
这里我定义了三个按钮,分别为“上一页”、“当前页”、“下一页”,其中“当前页”在翻页过程中会不断计算更新页面展示。然后将几个按钮要添加到ARJS 的viewer对象上:
  1. viewer = this.$refs.reportViewer.Viewer();
  2. this.designerHidden = true;
  3. [ prevPageButton, pageCount, nextPageButton ].forEach((item) => {
  4.       viewer.toolbar.addItem(item);
  5. })
  6. viewer.toolbar.updateLayout({default: ["$zoom", "$split", "$print","$prevPageButton", "$pageCount", "$nextPageButton"]});
复制代码

api的使用部分不再赘述,可以参考帮助文档:https://demo.grapecity.com.cn/ac ... tarted/ResourceGuid


2、分页展示数据
自定义按钮之后我们就需要去实现如何分页取数据,只展示当页数据。我们需要提前计算好每页能够展示多少条数据,比如我这里每页展示29条数据,所以每次从后端数据中取出29条数据来传给报表展示:
  1. let currentPage  = 1;
  2. //每页展示的数据条数
  3. let once = 29;
  4. //计算需要展示的总页数
  5. const totalPage = salesData.length % once ? Math.floor(salesData.length / once) + 1 : Math.floor(salesData.length / once);
复制代码
初始预览时,传给报表前29条数据:
  1. openReportView(salesData.slice(0, 29));

  2. function openReportView(data) {
  3.       definition.DataSources[0].ConnectionProperties.ConnectString = "jsondata=" + JSON.stringify(data);
  4.       viewer.open(definition);
  5. }
复制代码
在翻页时再判断逻辑,将数据分段传给报表文件,这里逻辑需要定义在之前定义的button提供的action接口中,同时定义好翻页数据逻辑之后,我们也需要更新当前页的展示:
  1. const prevPageButton = {
  2.       key: '$prevPageButton',
  3.       text: "上一页",
  4.       title: "prevPageButton",
  5.       enabled: true,
  6.       action: function () {
  7.         if(currentPage === 1) {
  8.           return null;
  9.         } else {
  10.           currentPage --;
  11.           let data = salesData.slice((currentPage-1) * once, currentPage * once);
  12.           openReportView(data);
  13.           pageCount.onUpdate([], pageCount);
  14.         }
  15.       }
  16.     };
  17.     const nextPageButton = {
  18.       key: '$nextPageButton',
  19.       text: "下一页",
  20.       title: "nextPageButton",
  21.       enabled: true,
  22.       //action接口中实现更新每次展示的数据逻辑
  23.       action: function () {
  24.         if(currentPage === totalPage) {
  25.           return null;
  26.         } else  {
  27.           currentPage ++;
  28.           let data = currentPage === totalPage ? salesData.slice((currentPage-1) * once, salesData.length) : salesData.slice((currentPage-1) * once, currentPage * once);
  29.           openReportView(data);
  30.           //调用更新展示当前页号的逻辑
  31.           pageCount.onUpdate([], pageCount);
  32.         }
  33.       }
  34.     };
  35.     const pageCount = {
  36.       key: '$pageCount',
  37.       text: `1/ ${totalPage}`,
  38.       title: "pageCount",
  39.       enabled: true,
  40.       //实现更新页号的逻辑
  41.       onUpdate: function (args, currentItem) {
  42.         currentItem.text = `${currentPage}/${totalPage}`;
  43.       }
  44.     };
复制代码


三、效果对比
至此我们分页展示大数据量报表的逻辑就已经实现完成了。让我们来对比看看效果吧!

未分页展示数据前:



分页展示数据:


可以看到上方两个GIF图有明显的对比,未分页前点击预览之后有两秒左右的空白加载时间,而分页之后,点击预览数据立刻呈现出来了。这里我的测试数据有一万多行,那么当后端传回的数据超过一万或者更多时,前期加载时间会更多,此时这种分页加载的方式就十分有用,更快的让数据呈现在用户眼前。


完整demo:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

10 个回复

倒序浏览
jklin
注册会员   /  发表于:2022-4-2 08:51:00
推荐
分页报表对业务部门使用来说不直观,有没有不分页的方案。
回复 使用道具 举报
James.Lv讲师达人认证 悬赏达人认证 活字格认证 Wyn认证
超级版主   /  发表于:2022-4-2 09:44:43
板凳
jklin 发表于 2022-4-2 08:51
分页报表对业务部门使用来说不直观,有没有不分页的方案。

您好,我们报表本身有自带的分页模式和不分页模式渲染,这个您可以灵活选择

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 使用道具 举报
jklin
注册会员   /  发表于:2022-4-2 10:00:16
地板
James.Lv 发表于 2022-4-2 09:44
您好,我们报表本身有自带的分页模式和不分页模式渲染,这个您可以灵活选择

我是指在楼主说的6、7000行的情况下的不分页优化方案
回复 使用道具 举报
James.Lv讲师达人认证 悬赏达人认证 活字格认证 Wyn认证
超级版主   /  发表于:2022-4-14 14:24:17
6#
jklin 发表于 2022-4-2 10:00
我是指在楼主说的6、7000行的情况下的不分页优化方案

不分页模式在大数据量下可能不分页模式不是太好,我觉得在大数据量可以采用连续模式进行报表展示,其本质还是分页,不过展示效果是通过鼠标滚动向下滑动查看

可以参考示例:
https://demo.grapecity.com.cn/ac ... ontinuous#timestamp


回复 使用道具 举报
zen
注册会员   /  发表于:2023-9-13 15:45:31
7#
如果报表涉及到分组,这样分页也可以吗?
回复 使用道具 举报
Felix.LiWyn认证
超级版主   /  发表于:2023-9-13 17:31:57
8#
这种其实只是针对于大数据量明细表能好一点,如果您还有分组分页

就像您说的,首先都不知道每一页展示多少,所以自然不好判断每次传多少数据。
当然如果您能直接准确的计算出每一页需要多少数据,就可以用这个方法,然后每次点下一页的时候去传递对应的数据,也不是不可以。但是就得咱们根据自己的情况去计算
回复 使用道具 举报
zen
注册会员   /  发表于:2023-9-13 18:17:56
9#
Felix.Li 发表于 2023-9-13 17:31
这种其实只是针对于大数据量明细表能好一点,如果您还有分组分页

就像您说的,首先都不知道每一页展示多 ...

系统报表都会有大量数据打印,涉及到分组,这种有什么好的解决方案吗?现在预览的时候8万条就卡死了。
回复 使用道具 举报
Felix.LiWyn认证
超级版主   /  发表于:2023-9-14 09:23:23
10#
针对您的问题有两种解决方案更好:

1.使用参数控制数据量。
比如您的原始数据是10w条数据。现在展示3w页,您可以加一个参数,然后参数作用于您的接口或者直接在数据集上过滤数据。比如参数默认值是1-10.然后选1的时候拿0-1w的数据。选2的时候拿1-2w的数据,以此类推。每次只拿部分,也展示部分,这样效果会更好。

2.可以使用另一款报表软件-wyn报表模块,您可以看下面的截图:

可以看到其实和ARJS的界面一模一样,包括设计以及属性等其实都一样。区别在于ARJS是纯前端渲染的,wyn-报表模块是后端开发的,所以它的展示性能会更好,包括导出加载速度,都比ARJS性能强,用这个会更好。
相关可以查看这个:https://www.grapecity.com.cn/sol ... /docs/create-report
产品查看这个:https://www.grapecity.com.cn/solutions/wyn

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 使用道具 举报
zen
注册会员   /  发表于:2023-9-14 15:04:17
11#
Felix.Li 发表于 2023-9-14 09:23
针对您的问题有两种解决方案更好:

1.使用参数控制数据量。

好的,谢谢
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 立即注册
返回顶部