[Interview question] How to efficiently render large amounts of data in front-end development?

Front-end interview question bank ( essential for interviews) Recommended: ★★★★★            

Address: Front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

In daily work, it is rare to encounter a scenario where a large amount of data is inserted into a page at one time. There are similar scenarios in the offline development (hereinafter referred to as offline) product of the data stack. This article will share a front-end development idea in an actual scenario to achieve efficient data rendering and improve page performance and user experience.

1. Scene introduction

  In the offline data development module, users can write sql in the sql editor and then  整段运行/分段运行 execute sql. After clicking  整段运行 and printing the success log and displaying the results, the page was stuck for a while, mainly due to the lag in the editor writing.

2. Performance issues

  When we were solving  sql 最大运行行数 the problem, we discovered the above scenarios that required performance optimization. First, let’s sort out the design logic of the current code: 

file

  • The front end passes the selected sql to the server, and the server returns a jobId that is scheduled to run;
  • The front end then polls the server with the jobId to query the execution status of the task;
  • When the polling task is completed, if there is a query statement in the selected sql, the server will return an array set of sqlId in the order of the select statement;
  • The front end is based on a set of n sqlIds and can concurrently send n  selectData requests;
  • selectData Render data after all  requests are completed;

In order to ensure that the final display order of the results is consistent with the order of the select statement, we add the Promise.allsettled method to the simple sqlIdList loop method, so that the request order of n selectData is consistent with the order of the select statement.

file

  From the above logic, it can be seen that the problem may be that if there are a large number of select statements in the selected sql, a large number of interfaces will be requested after the "whole run" is completed, and then the rendering will be performed after all the requests are  selectData completed  selectData . At this time, there will be a scenario where a large amount of data is inserted into the page at once. So, how do we solve the above problems?

3. Solution ideas

  It can be seen that there are two main problems with the above logic:

  • 1. Bulk request  selectData interface;
  • 2. Centralized data rendering.

1. Task grouping

  Still by  Promise.allsettled getting the results returned by all  selectData interfaces, we regard the original centralized rendering as a big task, and we split the task into a single  selectData result rendering task; and then group the individual tasks according to the actual situation, such as two groups, After rendering one group, render the next group. After splitting the tasks, the priority of the tasks is involved. The priority determines which task is executed first. The most original "preemptive rotation" is used here, and  sqlIdList the SQL order in the editor is retained in the order.

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);
});

2. Request grouping + task grouping

  The large batch request interface in question 1  selectData is also a breakthrough point. We can group the requests and request the  selectData interface with a fixed number of sqlIds each time. For example, each group requests the results of 6 sqlIds, and renders after all the requests of the current group are completed; in order to ensure the best effect, task grouping is also introduced here ideas.

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);

3. Request grouping

  The code of the previous solution is too difficult to understand when written. It belongs to the logic of writing it in the morning and forgetting it in the afternoon. Comments are also difficult to write, which is not conducive to maintenance. Based on the actual situation, we try to group the requests only to see the effect.

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

4. Understanding of ideas

1. To solve the problem of large data volume rendering, common methods include: time slicing, virtual list, etc.; 2. To
solve the problem of synchronous blocking, common methods include: task decomposition, asynchronous, etc.;
3. If a task takes a long time to execute If so, from an optimization perspective, we usually consider decomposing the task into a series of subtasks.

  In the task grouping section, we set the time interval of setTimeout to 100ms, that is, I think the rendering can be completed within 100ms at the fastest; but assuming that the rendering is completed in less than 100ms, then it is necessary to wait for a while, which is not true necessary. At this time, you can consider the window.requestAnimationFrame  method.

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

  The request grouping in the third section actually achieves the effect of rendering task grouping. This article is more about providing a solution. The above method is also based on the understanding and practice of time slicing.

5. Write at the end

  In software development, performance optimization is an important aspect, but it is not the only pursuit. Often, multiple factors need to be considered, including functional requirements, maintainability, security, and so on. Depending on the situation, a combination of techniques and strategies are used to find the best solution.

Front-end interview question bank ( essential for interviews) Recommended: ★★★★★            

Address: Front-end interview question bank

[National Day Avatar] - National Day patriotic programmer avatar! always one option fit for you!

Guess you like

Origin blog.csdn.net/weixin_42981560/article/details/132815711