加载10k+行至AG Grid透视表时页面无响应的前端优化咨询
AG Grid透视表前端性能优化方案(无需修改后端)
针对你遇到的透视表拖拽字段后页面无响应问题,结合你的代码场景,以下是纯前端的优化方案:
1. 限制透视维度数量,避免组合爆炸
当拖拽过多行/列字段时,透视后的行/列组合数会呈指数级增长,直接导致DOM渲染量过载。建议在交互层添加限制:
- 限制行字段最多3个、列字段最多3个,超过时提示用户
- 在
updateTableColumns方法开头增加判断逻辑:
if (this.selectedRows.length > 3) { alert('行字段最多支持3个,过多会导致性能下降'); return; } if (this.selectedColumns.length > 3) { alert('列字段最多支持3个,过多会导致性能下降'); return; }
2. 调整Grid渲染配置,最大化虚拟化效果
你的Grid配置已开启虚拟化,但部分设置削弱了效果,修改如下:
HTML模板修改
- 移除
min-height:150vh,改为固定视口高度,避免Grid高度异常导致虚拟化失效:
style="width: 100%; height: calc(100vh - 80px);"
- 默认关闭所有组展开,减少初始渲染行数:
[groupDefaultExpanded]="0" [pivotDefaultExpanded]="0"
- 暂时关闭非必要的
enableCharts功能,需要时再手动开启:
[enableCharts]="false"
3. 优化Grid更新逻辑,减少不必要重绘
你的updateTableColumns方法存在多次触发Grid重绘的操作,修改后合并更新步骤:
updateTableColumns() { if (!this.gridApi) return; if (this.selectedRows.length > 0) { // 维度数量限制逻辑... this.gridApi.showLoadingOverlay(); this.updateColumnDefs(); // 先设置行数据,再设置列定义,合并更新步骤 if (this.filteredCaseInfoDispList?.length) { this.gridApi.setRowData(this.filteredCaseInfoDispList); } this.gridApi.setColumnDefs(this.colDefs); this.reportBuilderUtil.setLimitConfig( this.gridApi, this.selectedRows, this.selectedColumns ); // 延迟处理Overlay,避免多次触发渲染 setTimeout(() => { this.gridApi.hideOverlay(); if (!this.filteredCaseInfoDispList?.length) { this.gridApi.showNoRowsOverlay(); } }, 100); } else { this.gridApi.setColumnDefs([]); this.gridApi.showNoRowsOverlay(); } // 移除不必要的markForCheck,Angular变更检测会自动处理 // this.cdr.markForCheck(); }
- 移除
gridApi.refreshCells()调用:透视模式下,设置列定义和行数据后Grid会自动重新计算渲染,手动刷新会增加额外开销
4. 异步处理数据过滤,避免阻塞主线程
你的filterTableData是同步遍历全量数据,数据量大时会阻塞UI。改为分批异步处理:
filterTableData() { const totalData = this.caseInfoDispList; const filters = this.selectedFilters; const isMatchAll = this.isMatchAllFilters(); const batchSize = 1000; let currentIndex = 0; this.filteredCaseInfoDispList = []; const processBatch = () => { const endIndex = Math.min(currentIndex + batchSize, totalData.length); const batch = totalData.slice(currentIndex, endIndex); const filteredBatch = batch.filter(item => { if (filters.length === 0) return true; const boolResult = filters.map(filter => this.reportBuilderUtil.isMatchFilter(filter, item)); return isMatchAll ? boolResult.every(v => v) : boolResult.some(v => v); }); this.filteredCaseInfoDispList = [...this.filteredCaseInfoDispList, ...filteredBatch]; currentIndex = endIndex; if (currentIndex < totalData.length) { requestIdleCallback(processBatch); } else { this.gridApi?.setRowData(this.filteredCaseInfoDispList); } }; requestIdleCallback(processBatch); }
- 利用
requestIdleCallback在浏览器空闲时分批处理过滤,避免主线程阻塞
5. 减少不必要的变更检测
移除代码中多次调用的cdr.markForCheck():Angular的变更检测会自动监听colDefs、filteredCaseInfoDispList等绑定属性的变化,手动调用反而会增加额外的检测开销。
内容的提问来源于stack exchange,提问作者Tracy
相关产品推荐
相关产品推荐

