From 2e9093ef7d360ac1562574a8de0009f02bcfc6b4 Mon Sep 17 00:00:00 2001 From: yangdan Date: Fri, 28 Mar 2025 10:46:33 +0800 Subject: [PATCH 1/2] feat: improve the performance of exporting excel --- packages/vtable-export/src/excel/index.ts | 65 ++++++++++++++++------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/packages/vtable-export/src/excel/index.ts b/packages/vtable-export/src/excel/index.ts index bbc8ff888a..870d9c2d9e 100644 --- a/packages/vtable-export/src/excel/index.ts +++ b/packages/vtable-export/src/excel/index.ts @@ -46,30 +46,59 @@ export async function exportVTableToExcel(tableInstance: IVTable, options?: Expo const mergeCells = []; const mergeCellSet = new Set(); - for (let col = minCol; col <= maxCol; col++) { - const colWith = tableInstance.getColWidth(col); - columns[col] = { width: colWith / 6 }; - for (let row = minRow; row <= maxRow; row++) { - if (col === minCol) { - const rowHeight = tableInstance.getRowHeight(row); - const worksheetRow = worksheet.getRow(row + 1); - // worksheetRow.height = rowHeight * 0.75; - worksheetRow.height = rowHeight; - } + const SLICE_SIZE = 100; + let currentRow = minRow; + + function processSlice(deadline: IdleDeadline) { + return new Promise(async resolve => { + while (currentRow <= maxRow && deadline.timeRemaining() > 0) { + const endRow = Math.min(currentRow + SLICE_SIZE - 1, maxRow); + for (let col = minCol; col <= maxCol; col++) { + const colWidth = tableInstance.getColWidth(col); + if (columns[col] === undefined) { + columns[col] = { width: colWidth / 6 }; + } + for (let row = currentRow; row <= endRow; row++) { + if (col === minCol) { + const rowHeight = tableInstance.getRowHeight(row); + const worksheetRow = worksheet.getRow(row + 1); + // worksheetRow.height = rowHeight * 0.75; + worksheetRow.height = rowHeight; + } - await addCell(col, row, tableInstance, worksheet, workbook, options); + await addCell(col, row, tableInstance, worksheet, workbook, options); - const cellRange = tableInstance.getCellRange(col, row); - if (cellRange.start.col !== cellRange.end.col || cellRange.start.row !== cellRange.end.row) { - const key = `${cellRange.start.col},${cellRange.start.row}:${cellRange.end.col},${cellRange.end.row}}`; - if (!mergeCellSet.has(key)) { - mergeCellSet.add(key); - mergeCells.push(cellRange); + const cellRange = tableInstance.getCellRange(col, row); + if (cellRange.start.col !== cellRange.end.col || cellRange.start.row !== cellRange.end.row) { + const key = `${cellRange.start.col},${cellRange.start.row}:${cellRange.end.col},${cellRange.end.row}`; + if (!mergeCellSet.has(key)) { + mergeCellSet.add(key); + mergeCells.push(cellRange); + } + } + } } + currentRow = endRow + 1; } - } + + if (currentRow > maxRow) { + resolve(); + } else { + requestIdleCallback(async nextDeadline => { + await processSlice(nextDeadline); + resolve(); + }); + } + }); } + await new Promise(resolve => { + requestIdleCallback(async deadline => { + await processSlice(deadline); + resolve(); + }); + }); + worksheet.columns = columns; mergeCells.forEach(mergeCell => { worksheet.mergeCells( From 91cbf840eebdc5f5d51c564d93b365f5ab979ee0 Mon Sep 17 00:00:00 2001 From: yangdan Date: Mon, 31 Mar 2025 12:29:52 +0800 Subject: [PATCH 2/2] feat: add optimization parameter to exporting excel --- docs/assets/guide/en/export/excel.md | 9 ++++++ docs/assets/guide/zh/export/excel.md | 9 ++++++ packages/vtable-export/src/excel/index.ts | 36 +++++++++++++++-------- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/docs/assets/guide/en/export/excel.md b/docs/assets/guide/en/export/excel.md index 4eb5e54a3a..b93c2da87c 100644 --- a/docs/assets/guide/en/export/excel.md +++ b/docs/assets/guide/en/export/excel.md @@ -137,3 +137,12 @@ const excelOption = { }; await downloadExcel(await exportVTableToExcel(tableInstance, excelOption)); ``` + +### equestIdleCallback + +`@visactor/vtable-export` uses the `exceljs` library as a tool for exporting Excel files. If you need tosolve the impact on page performance during the export process, you can set the `optimization` parameter to enable `requestIdleCallback`. + +```js +const excelOption = {}; +await downloadExcel(await exportVTableToExcel(tableInstance, excelOption, true)); +``` diff --git a/docs/assets/guide/zh/export/excel.md b/docs/assets/guide/zh/export/excel.md index 60ab477791..57e0f84c78 100644 --- a/docs/assets/guide/zh/export/excel.md +++ b/docs/assets/guide/zh/export/excel.md @@ -137,3 +137,12 @@ const excelOption = { }; await downloadExcel(await exportVTableToExcel(tableInstance, excelOption)); ``` + +### equestIdleCallback + +`@visactor/vtable-export`使用`exceljs`库作为导出 Excel 文件的工具,如果需要解决导出对页面性能影响,可以设置`requestIdleCallback`的启用参数`optimization` + +```js +const excelOption = {}; +await downloadExcel(await exportVTableToExcel(tableInstance, excelOption, true)); +``` diff --git a/packages/vtable-export/src/excel/index.ts b/packages/vtable-export/src/excel/index.ts index 870d9c2d9e..8b6d556d7e 100644 --- a/packages/vtable-export/src/excel/index.ts +++ b/packages/vtable-export/src/excel/index.ts @@ -33,7 +33,15 @@ export type ExportVTableToExcelOptions = { skipImageExportCellType?: SkipImageExportCellType[]; }; -export async function exportVTableToExcel(tableInstance: IVTable, options?: ExportVTableToExcelOptions) { +function requestIdleCallbackPromise(options?: IdleRequestOptions) { + return new Promise((resolve) => { + requestIdleCallback((deadline) => { + resolve(deadline); + }, options); + }); +} + +export async function exportVTableToExcel(tableInstance: IVTable, options?: ExportVTableToExcelOptions, optimization = false) { const workbook = new ExcelJS.Workbook(); const worksheet = workbook.addWorksheet('sheet1'); worksheet.properties.defaultRowHeight = 40; @@ -49,9 +57,9 @@ export async function exportVTableToExcel(tableInstance: IVTable, options?: Expo const SLICE_SIZE = 100; let currentRow = minRow; - function processSlice(deadline: IdleDeadline) { + function processSlice(deadline?: IdleDeadline) { return new Promise(async resolve => { - while (currentRow <= maxRow && deadline.timeRemaining() > 0) { + while (currentRow <= maxRow && (!optimization || (deadline?.timeRemaining() > 0))) { const endRow = Math.min(currentRow + SLICE_SIZE - 1, maxRow); for (let col = minCol; col <= maxCol; col++) { const colWidth = tableInstance.getColWidth(col); @@ -84,19 +92,23 @@ export async function exportVTableToExcel(tableInstance: IVTable, options?: Expo if (currentRow > maxRow) { resolve(); } else { - requestIdleCallback(async nextDeadline => { - await processSlice(nextDeadline); - resolve(); - }); + let nextDeadline: IdleDeadline | undefined; + if (optimization) { + nextDeadline = await requestIdleCallbackPromise() + } + await processSlice(nextDeadline); + resolve(); } }); } - await new Promise(resolve => { - requestIdleCallback(async deadline => { - await processSlice(deadline); - resolve(); - }); + await new Promise(async resolve => { + let deadline: IdleDeadline | undefined; + if (optimization) { + deadline = await requestIdleCallbackPromise() + } + await processSlice(deadline); + resolve(); }); worksheet.columns = columns;