前端开发进阶:前端开发中如何高效渲染大数据量?

news2025/1/14 18:40:26

在日常工作中,有时会遇到一次性往页面中插入大量数据的场景,在数栈的离线开发(以下简称离线)产品中,就有类似的场景。本文将通过分享一个实际场景中的前端开发思路,介绍当遇到大量数据时,如何实现高效的数据渲染,以达到提升页面性能和用户体验的目的。

渲染大数据量时遇到的问题

在离线的数据开发模块,用户可以在 SQL 编辑器中编写 SQL,再通过整段运行/分段运行来执行 SQL。在点击整段运行后,从运行成功日志打印后到展示结果的过程中,有一段时间页面会很卡顿,主要表现为编辑器编写卡顿。

file

我们是在解决 SQL 最大运行行数问题时,发现了上述需要进行性能优化的场景。

先来梳理下当前代码的设计逻辑:

file

· 前端将选中的 SQL 传递给服务端,服务端返回一个调度运行的 jobId

· 前端接着以该 jobId 轮询服务端,查询任务的执行状态

· 当轮询到任务已完成时,选中的 SQL 中如果有查询语句,服务端则会按 select 语句的顺序返回一个 sqlId 的数组集合

· 前端基于n个 sqlId 的集合,并发 n个 selectData 的请求

· 所有的 selectData 请求完成后渲染数据

为了保证结果最终的展示顺序和 select 语句顺序一致,我们为单纯的 sqlIdList 循环方法加上了 Promise.allsettled 的方法,使得n个 selectData 的请求顺序和 select 语句顺序一致。

file

由上述逻辑可以看出,问题可能出现在如果选中的 SQL 中有大量 select 语句的话,会在「整段运行」完成后大批量请求 selectData 接口,再等待所有 selectData 请求完成后,集中进行渲染。此时,就会出现一次性往页面中插入大量数据的场景,导致卡顿。那么,我们怎么解决上述问题呢?

解决思路

可以看出,上述逻辑主要有两个问题:大批量请求 selectData 接口和集中性数据渲染。我们通过如下所示的解决思路去处理这些问题。

任务分组

依旧通过 Promise.allsettled 拿到所有 selectData 接口返回的结果,将原先集中渲染看作是一个大任务,我们将任务拆分成单个的 selectData 结果渲染任务。再根据实际情况,对单个任务进行分组,比如两个一组,渲染完一组再渲染下一组。

拆分完任务,就涉及到了任务的优先级问题,优先级决定了哪个任务先执行。这里采用最原始的“抢占式轮转”,按 sqlIdList 的顺序保留编辑器中的 SQL 顺序。

Promise.allSettled(promiseList).then((results = []) => {
    const renderOnce = 2; // 每组渲染的结果 tab 数量
    const loop = (idx) => {
        if (promiseList.length <= idx) return;
        results.slice(idx, idx + renderOnce).forEach((item, idx) => {
            if (item.status === 'fulfilled') {
                handleResultData(item?.value || {}, sqlIdList[idx]?.sqlId);
            } else {
                console.error(
                    'selectExecResultDataList Promise.allSettled rejected',
                    item.reason
                );
            }
        });
        setTimeout(() => {
            loop(idx + renderOnce);
        }, 100);
    };
    loop(0);
});

请求分组 + 任务分组

问题中的大批量请求 selectData 接口,也是一个突破点。我们可以将请求进行分组,每次以固定数量的 sqlId 去请求 selectData 接口,比如每组请求 6 个 sqlId 的结果,当前组的请求全部结束后再进行渲染。为了保证效果最优,这里也引入任务分组的思路。

const requestOnce = 6; // 每组请求的数量
// 将一维数组转换成二维数组
const sqlIdList2D = convertTo2DArray(sqlIdList, requestOnce);
const idx2D = 0; // sqlIdList2D 的索引

const requestLoop = (index) => {
    if (!sqlIdList2D[index]) return;
    const promiseList = sqlIdList2D[index].map((item) =>
        selectExecResultData(item?.sqlId)
                                              );
    Promise.allSettled(promiseList)
        .then((results = []) => {
            const renderOnce = 2; // 每组渲染的结果 tab 数量

            const loop = (idx) => {
                if (promiseList.length <= idx) return;
                results.slice(idx, idx + renderOnce).forEach((item, idx) => {
                    if (item.status === 'fulfilled') {
                        handleResultData(item?.value || {}, sqlIdList[idx]?.sqlId);
                    } else {
                        console.error(
                            'selectExecResultDataList Promise.allSettled rejected',
                            item.reason
                        );
                    }
                });
                setTimeout(() => {
                    loop(idx + renderOnce);
                }, 100);
            };
            loop(0);
        })
        .finally(() => {
            requestLoop(index + 1);
        });
};
requestLoop(idx2D);

请求分组

上一种方案的代码相对来说又些难以理解,属于上午写,下午忘的逻辑,注释也不好写,不利于维护。基于实际情况,我们尝试下仅对请求作分组处理,看看效果。

const requestOnce = 3; // 每组请求的数量
// 将一维数组转换成二维数组
const sqlIdList2D = convertTo2DArray(sqlIdList, requestOnce);
const idx2D = 0; // sqlIdList2D 的索引

const requestLoop = (index) => {
    if (!sqlIdList2D[index]) return;
    const promiseList = sqlIdList2D[index].map((item) =>
        selectExecResultData(item?.sqlId)
                                              );
    Promise.allSettled(promiseList)
        .then((results = []) => {
            results.forEach((item, idx) => {
                if (item.status === 'fulfilled') {
                    handleResultData(item?.value || {}, sqlIdList[idx]?.sqlId);
                } else {
                    console.error(
                        'selectExecResultDataList Promise.allSettled rejected',
                        item.reason
                    );
                }
            });
        })
        .finally(() => {
            requestLoop(index + 1);
        });
};
requestLoop(idx2D);

file

解决思路解析

· 解决大数据量渲染的问题,常见方法有:时间分片、虚拟列表等

· 解决同步阻塞的问题,常见方法有:任务分解、异步等

· 如果某个任务执行时间较长的话,从优化的角度,我们通常会考虑将该任务分解成一系列的子任务

在任务分组一节,我们将 setTimeout 的时间间隔设置为 100ms,也就是我认为最快在 100ms 内能完成渲染。但假设不到 100ms 就完成了渲染,那么就需要白白等待一段时间,这是没有必要的,这时可以考虑 window.requestAnimationFrame 方法。

- setTimeout(() => {
+ window.requestAnimationFrame(() => {
      loop(idx + renderOnce);
- }, 100);
+ });

第三节的请求分组,实际上已经达到了渲染任务分组的效果。本文更多的是提供一个解决思路,上述方式也是基于对时间分片的理解实践。

在软件开发中,性能优化是一个重要的方面,但并不是唯一追求,往往还需要考虑多个因素,包括功能需求、可维护性、安全性等等。根据具体情况,综合使用多种技术和策略,找到最佳的解决方案,才是最终目的。

《数栈产品白皮书》:https://www.dtstack.com/resources/1004?src=szsm

《数据治理行业实践白皮书》下载地址:https://www.dtstack.com/resources/1001?src=szsm

想了解或咨询更多有关袋鼠云大数据产品、行业解决方案、客户案例的朋友,浏览袋鼠云官网:https://www.dtstack.com/?src=szcsdn

同时,欢迎对大数据开源项目有兴趣的同学加入我们,一起交流最新开源技术信息,号码:30537511,项目地址:https://github.com/DTStack

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【1782. 统计点对的数目】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个无向图&#xff0c;无向图由整数 n &#xff0c;表示图中节点的数目&#xff0c;和 edges 组成&#xff0c;其中 edges[i] [ui, vi] 表示 ui 和 vi 之间有一条无向边。同时给你一个代表查询…

display设为inline-block时引发的高度问题,大坑

今天在写小程序&#xff0c;点击让这个遮罩层显示&#xff0c;结果一直下移&#xff0c;莫名其妙。 解决方案&#xff1a; 在元素的CSS中添加&#xff1a;vertical-align: bottom;

minAreaRect 函数新版与旧版对比

minAreaRect 函数 cv2.minAreaRect (InputArray_points) 入参 points 是点的集合&#xff0c;如轮廓 返回值 RotatedRect,带角度的旋转矩形框,其值形如(center(x,y), (width, height), angle of rotation ) center(x,y), (width, height)分别是旋转矩形框中心的坐标和矩…

chrome浏览器账号密码输入框自动填充时背景色不变

处理前 使用延时的方式解决 .login-box input,password:-webkit-autofill .login-box input,password:-webkit-autofill:hover, .login-box input,password:-webkit-autofill:focus, .login-box input,password:-webkit-autofill:active {-webkit-transition-delay: 999999…

【HMS Core】在线语种检测返回结果错误

【关键字】 在线语种检测、机器学习 【问题描述】 集成在线语种检测服务&#xff0c;检测蒙古文之后&#xff0c;返回结果为中文 【问题分析】 1、在线语种服务目前不支持蒙古文&#xff0c;具体可见官网语种支持列表&#xff1a; 【ML Kit】语种检测支持的语言列表 2、目前…

【JAVA毕设|课设】基于SpringBoot+vue的在线考试系统-以计算机网络为例,可自行录入题库-附下载地址

基于SpringBootvue的在线考试系统-以计算机网络为例&#xff0c;可自行录入题库 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着信息技术的迅猛发展&#xff0c;教育行业正面临着巨大的变革和挑战。…

RTP/RTCP的 NACK, PLI,SLI,FIR

1&#xff0c;概述 在网络环境不是太好的情况下&#xff0c;比如网络拥塞比较严重&#xff0c;丢包率可能比较高&#xff0c;简单实用NACK重传的机制&#xff0c;这样就会有大量的RTCP NACK报文&#xff0c;发送端收到相应的报文&#xff0c;又会发送大量指定的RTP报文&#x…

5G NR:PRACH时域资源

PRACH occasion时域位置由高层参数RACH-ConfigGeneric->prach-ConfigurationIndex指示&#xff0c;根据小区不同的频域和模式&#xff0c;38.211的第6.3.3节中给出了prach-ConfigurationIndex所对应的表格。 小区频段为FR1&#xff0c;FDD模式(paired频谱)/SUL&#xff0c;…

【前端从0开始】JavaSript——循环控制语句

循环控制语句 while语句 While 循环会在指定条件为真时循环执行代码块。 While循环&#xff0c;先进行条件判断&#xff0c;再执行循环体的代码 while (条件表达式){循环体 }注意&#xff1a;当前循环中&#xff0c;如果不满足条件&#xff0c;一次都不会执行 var i 1; whi…

利用tidevice+mysql+grafana实现ios性能测试

利用tidevicemysqlgrafana实现ios性能测试 1.什么是tidevice&#xff1f; tidevice是一个可以和ios设备进行通信的工具&#xff0c;提供以下功能&#xff1a; 截图获取手机信息ipa包的安装和卸载根据bundleID 启动和停止应用列出安装应用信息模拟Xcode运行XCTest&#xff0c…

学会Mybatis框架:让你的代码更具灵活性、可维护性、安全性和高效性【二.动态SQL】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Mybatis动态SQL如何应用 1.需求 2.…

2022美亚杯个人赛复刻

案件详情 于2022年10月&#xff0c;有市民因接获伪冒快递公司的电邮&#xff0c;不慎地于匪徒架设的假网站提供了个人信用咭资料导致经济损失。 警方追查下发现当中一名受骗市民男子李大輝 (TaiFai) 的信用卡曾经被匪徒在区内的商舖购物。 后来警方根据IP地址&#xff0c;锁定…

js实现定时器

用原生js实现一个倒计时效果.最下面有全部源码,需要自取 js语法: setTimeout:定时器 document.getElementById:Document的方法 getElementById()返回一个匹配特定 ID的元素。由于元素的 ID 在大部分情况下要求是独一无二的&#xff0c;这个方法自然而然地成为了一个高效查找特…

第三篇:对话框窗口部件 QDialog

对话框窗口部件 QDialog 对话框&#xff08;Dialog&#xff09;是计算机图形用户界面&#xff08;GUI&#xff09;中的一种常见窗口类型&#xff0c;通常用于与用户进行交互、获取信息、提供反馈或执行特定任务。对话框的主要目的是与用户进行短期的、有限的交互&#xff0c;以…

【校招VIP】产品职位理解之团队的配合和推进

考点介绍&#xff1a; 对于简历上有实习经验的同学&#xff0c;对于团队配合和项目推进是一个非常常见的提问点。产品经理经常会面临项目延期&#xff0c;无法上线的情况。基于此&#xff0c;产品经理应该做些什么来保障项目按时上线呢&#xff1f; 『产品职位理解之团队的配合…

THUHCSI人机语音交互实验室9篇论文被语音旗舰国际会议INTERSPEECH录用

2023年ISCA国际语音通讯学会年会&#xff08;2023 Annual Conference of the International Speech Communication Association, INTERSPEECH 2023&#xff09;将于2023年8月20日-24日在爱尔兰都柏林召开&#xff0c;清华大学人机语音交互实验室&#xff08;THUHCSI&#xff09…

视频监控平台EasyCVR视频汇聚平台档案库房图书馆等可视化管理平台应用场景全面解析

档案是一种特殊的记录留存文献&#xff0c;具有珍贵的精神财富价值。它们是人类活动的真实见证&#xff0c;是辉煌时刻的历史记录&#xff0c;在社会发展和经济建设中发挥着至关重要的作用。 随着市场经济的不断发展和人类文明的飞速推进&#xff0c;档案的价值和作用变得越来…

【广州华锐互动】VR工厂消防安全演习提供了一种全新、生动的安全教育方式

在工业生产环境中&#xff0c;安全永远是首要的考虑因素。近年来&#xff0c;随着科技的发展&#xff0c;虚拟现实(VR)技术在各种领域的应用越来越广泛&#xff0c;包括教育和培训。其中&#xff0c;VR工厂消防安全演习就是一个典型的例子&#xff0c;它为员工提供了一种全新的…

msvcr120.dll丢失的解决方法,win10系统dll报错解决方法

今天&#xff0c;我将和大家分享一个在win10系统中经常遇到的问题&#xff1a;msvcr120.dll丢失。相信很多朋友在使用电脑的过程中都会遇到这个问题&#xff0c;那么如何解决呢&#xff1f;接下来&#xff0c;就让我为大家详细讲解一下解决方法。 首先&#xff0c;我们来了解一…

基于Spark+django的国漫推荐系统--计算机毕业设计项目

近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;随着各行业的不断发展&#xff0c;基…