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

这篇具有很好参考价值的文章主要介绍了前端开发进阶:前端开发中如何高效渲染大数据量?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

由上述逻辑可以看出,问题可能出现在如果选中的 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);

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

解决思路解析

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

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

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

在任务分组一节,我们将 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=szbky

同时,欢迎对大数据开源项目有兴趣的同学加入「袋鼠云开源框架钉钉技术qun」,交流最新开源技术信息,qun号码:30537511,项目地址:https://github.com/DTStack文章来源地址https://www.toymoban.com/news/detail-666266.html

到了这里,关于前端开发进阶:前端开发中如何高效渲染大数据量?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot进阶(19):探索ElasticSearch:如何利用Spring Boot轻松实现高效数据搜索与分析

            ElasticSearch是一款基于Lucene的开源搜索引擎,具有高效、可扩展、分布式的特点,可用于全文搜索、日志分析、数据挖掘等场景。Spring Boot作为目前最流行的微服务框架之一,也提供了对ElasticSearch的支持。本篇文章将介绍如何在Spring Boot项目中整合ElasticSearch,并展

    2024年02月11日
    浏览(44)
  • Spring Boot进阶(70):如何在Spring Boot中使用FastJson实现高效的JSON数据处理?

      随着互联网的发展,JSON(JavaScript Object Notation)已成为近年来使用最广泛的数据交换格式之一。为了提高JSON数据的处理效率,目前市面上常用的JSON解析库有Jackson、Gson、FastJson等。本文将介绍如何在Spring Boot中使用FastJson实现高效的JSON数据处理。   那么,具体如何实现

    2024年02月09日
    浏览(43)
  • 性能优化之-更高效的数据渲染

    前言:中心思想还是让请求的资源得到更快响应的方法,比如压缩资源,减少数据量的大小,缓存数据以减少请求数量,http/2让网络传输变得更快这些,下面就让我们来看看浏览器是如何解析这些数据,最终又是如何将他们渲染在屏幕上的?在数据量不变的情况下还有哪些可

    2024年02月09日
    浏览(37)
  • 前端秘法进阶篇----这还是我们熟悉的浏览器吗?(浏览器的渲染原理)

    目录 一.浏览器渲染原理 二.渲染时间点 三.渲染流水线 1.解析html(Parse HTML) 1.1解析成DOM树(document object model) 1.2解析成CSSOM树(css object model) 2.样式计算(Recalculate Style) 3.布局(Layout) 4.分层(Layer) 5. 绘制(Paint) 6.分块(Tiling) 7. 光栅化(Raster) 8. 画(Draw) 四.附加面试题 1.什么是 reflow? 2.什

    2024年02月21日
    浏览(33)
  • 前端如何安全的渲染HTML字符串?

    在现代的Web 应用中,动态生成和渲染 HTML 字符串是很常见的需求。然而,不正确地渲染HTML字符串可能会导致安全漏洞,例如跨站脚本攻击(XSS)。为了确保应用的安全性,我们需要采取一些措施来在安全的环境下渲染HTML字符串。本文将介绍一些安全渲染 HTML 字符串的最佳实

    2024年02月12日
    浏览(37)
  • 掌握前端框架,打造高效的开发流程

    在当今互联网时代,前端开发已经成为了一项非常重要的技能。随着互联网的快速发展,前端技术也在不断演进和更新。为了提高开发效率和代码质量,掌握前端框架已经成为了必备的技能之一。本文将介绍如何通过掌握前端框架,打造高效的开发流程,并通过一个实际案例

    2024年02月11日
    浏览(49)
  • 前端组件开发指南:构建可复用、高效的用户界面

    在现代Web开发中,前端组件扮演着重要的角色。它们是构建用户界面的基本构建块,能够使开发人员更高效地开发、测试和维护代码。本文将带您深入了解前端组件的概念、优势以及如何使用常见的前端框架构建可复用的组件。 前端组件是一种封装了HTML、CSS和JavaScript代码的

    2024年02月16日
    浏览(40)
  • fastadmin学习08-查询数据渲染到前端

    index.php查询,这个是前台的index.php 模板代码 结果

    2024年04月08日
    浏览(31)
  • 「网页开发|前端开发|Vue」07 前后端分离:如何在Vue中请求外部数据

    本文主要介绍两种在Vue中访问外部API获取数据的方式,通过让Vue通过项目外部的接口来获取数据,而不是直接由项目本身进行数据库交互,可以实现前端代码和后端代码的分离,让两个部分的代码编写更独立高效。 「网页开发|前端开发|Vue」01 快速入门:快速写一个Vue的

    2024年02月09日
    浏览(40)
  • 前端页面渲染多条数据长列表的性能优化

    后端一次性返回了10w条数据,前端该如何处理?长列表性能优化 这个问题其实是考察面试者对性能优化的理解。我们知道,对于大量数据渲染的时候,JS运算并不是性能的瓶颈,性能的瓶颈主要在于渲染阶段,所以页面的卡顿是由于同时渲染大量DOM所引起的。 简单聊一下 s

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包