Richard.Ma 发表于 2022-5-6 10:16:22

【常见问题】如何优化 SpreadJS 表格性能

本帖最后由 Richard.Ma 于 2022-5-27 22:03 编辑

SpreadJS 是一款高性能的电子表格控件。在大多数情况下,可以加载大数据量以及复杂公式计算的excel
下面的几种方法可以进一步优化 SpreadJS 以获得更快的加载、计算和与大量公式和/或数据交互的性能。以帮助您更好地优化 SpreadJS 性能。
1.使用Suspend/Resume Paint方法每次对 SpreadJS 进行任何更改时,都会刷新以显示更改。如果您一次进行许多更改,这可能会显着影响性能。在代码中首次初始化和设置电子表格时。一次进行了许多更改,因此在大多数情况下,suspendPaint 和 resumePaint 可以大大加快这一过程。suspendPaint 方法允许您在进行修改时停止重绘过程。完成所有更改后,您可以再调用 resumePaint 方法来重新绘制电子表格。
例子以下函数为所有行设置值:let setSampleData = (sheet,rowCount, colCount) => {
    for (let row = 0; row < rowCount; row++) {
      for (let col = 0; col < colCount; col++) {
            sheet.setValue(row, col, "data( " + row + ", " + col + " )");
      }
    }
};
这些代码需要 542 毫秒来更新十行和十列:setSampleData(spread.getActiveSheet(),10,10);
但是当使用与suspend/resumePaint相同的功能时,只需要19 ms即可完成。sheet.suspendPaint();
setSampleData(sheet,10, 10);
sheet.resumePaint();


2. 使用Suspend/Resume CalcService 方法每次我们更改公式或向工作表添加新公式时,SpreadJS 都会重新计算所有公式以更新结果。假设您的工作表或文件有许多公式,或者您正在为单元格设置或加载多个公式。在这种情况下,您可以使用 suspendCalcService 和 resumeCalcService 方法,它们可以极大地帮助提高性能。suspendCalcService 方法暂停所有计算。添加所有公式后,再使用 resumeCalcService 执行计算。
以下代码片段将第 1 行的 Sum Formula 公式应用于若干行列:let setFormulaData = (sheet,rowCount, colCount) => {
    for (let row = 1; row < rowCount; row++) {
      for (let col = 0; col < colCount; col++) {
            sheet.setFormula(row, col, "=SUM($A$1:$J$1)");
      }
    }
};
更新十行十列的公式需要 110 毫秒:sheet.suspendPaint()
setDummyFormula(sheet,10, 10);
sheet.resumePaint()
但是当使用suspendCalcService 和resumeCalcService 方法时。只需 50-60 毫秒。sheet.suspendPaint();
sheet.suspendCalcService();
setDummyFormula(sheet, 10, 10);
sheet.resumeCalcService(false);
sheet.resumePaint();


3. 使用 CalcOnDemand、DoNotRecalculateAfterLoad 标志
当一个文件加载到 SpreadJS 中时,spread 实例会重新计算工作簿中的公式,如果文件有很多公式,则会影响性能。为了防止这种情况,SpreadJS 支持在加载时使用 doNotRecalculateAfterLoad 标志。当加载时 doNotRecalculateAfterLoad 设置为 true 时,SpreadJS 在加载文件后不会重新计算工作簿。
在对单元格进行任何更改后,SpreadJS 会立即重新计算工作表,我们可以使用 calcOnDemand 标志来防止这种情况。calcOnDemand 可防止在工作表上进行不必要的重新计算
代码如下所示:workbook.fromJSON(jsonData,{
    doNotRecalculateAfterLoad:true
});
workbook.options.calcOnDemand=true;


4.减少迭代计算迭代计算,也称为循环引用,让您可以使用之前的计算结果重复运行计算。在某些情况下,广泛使用迭代计算可能会影响性能,因为这些计算是单线程的。另一个可能引起性能问题的原因是使用跨越多个工作表的循环引用。不要让 SpreadJS 计算引擎在工作表之间跳转,而是尝试将循环引用压缩到单个工作表,这有助于优化流程并避免不需要的额外计算。在 SpreadJS 中,您可以使用 iterativeCalculation 属性在工作表中启用迭代计算。您还可以通过设置 iterativeCalculationMaximumIterations 属性来指定公式重新计算的次数。此外,您还可以通过设置 iterativeCalculationMaximumChange 属性来限制两个计算值之间的最大变化量。


5. 使用增量加载导入大型 Excel/JSON 文件默认情况下,每次在 SpreadJS 中加载文件时,都会一次加载整个 JSON 文件。但是,一个大体积的文件可能需要更长的时间来加载,影响性能和用户体验。这时,SpreadJS增量加载功能刚好适用,它将以增量步骤导入工作簿,从而加快加载速度并为客户提供更好的体验。以下是使用增量加载的代码:function fromJSON(json) {
    spread.fromJSON(json,{
      incrementalLoading:
      {
            loading: function (progress, args) {
                console.log(progress, args.sheet.name());
            },
            loaded: function () {
                console.log("file loaded");
            }
      }
    });
}


6. 使用 SJS 表格和命名范围在 SpreadJS 中,您可以为单个单元格或一系列单元格赋予人类可读的名称,并通过名称而不是引用范围来引用这些单元格。SpreadJS 命名范围和表格是使单元格引用更容易的两个独特功能。
最显着的好处之一是表格会自动添加命名范围,这可以使您的公式更易于理解,例如:=SUM(MyTable[销售额])标准命名范围也可以独立使用,使数据更易于阅读。例如,使用具体含义的公式:=销售价格-成本价格比这样写更容易理解:=SUM(A1:A10)-SUM(G1:G10)


7. 将未使用的公式转换为静态值许多公式可能会导致 SpreadJS 工作簿变慢,如果您有甚至没有使用的公式,它们可能会导致速度变慢。如果您不需要公式,最好将它们转换为静态值(只需将公式结果粘贴为值)。


8. 使用数组公式数组公式允许您一次执行多个计算或在选定的单元格区域内多次执行一个或多个计算。这些公式可以有利于替换大量类似的公式。举个简单的例子,您可能有一个函数重复多个单元格,如 fn(A1, B1)、fn(A2, B2)、fn(A3, B3) 等,直到 fn(A1000, B1000)。您可以将其简化为 fn(A1:A1000, B1:B1000)。
数组公式将使其成为单个函数调用,而不是对同一个函数的数千次调用。这意味着要解析和计算的公式更少,因此加载时间更快。


9. 谨慎使用条件格式条件格式是一项功能,可让您将特定格式应用于满足特定条件的单元格。通常用作基于颜色的格式,以突出、强调或区分存储在电子表格中的数据和信息。虽然条件格式的公式设置非常灵活,但一些情况下可能也会严重影响性能。每次重新计算工作表时,都会重新评估条件格式规则。当这涉及许多单元格时,工作表可能会变得非常缓慢且无响应。例如:如果我们在条件格式中使用 ISBLANK(K1:Q200),它将遍历范围内的每个单元格,这意味着 ISBLANK 将被计算 1200*1200 = 1,440,000 次。从上面可以看到,条件格式中的单元格范围对性能的影响,我们可以将上面的公式替换为条件公式ISBLANK(K1),


10. 使用命名样式命名样式是可以与工作表上不同范围共享的样式对象。通常,当您有不同的单元格范围需要应用样式时,您可以为每个范围创建一个新的样式对象。但是,这样做可能会导致内存问题并影响性能。使用 setStyle 方法将在每次调用时创建一个新的样式对象,因此如果您对数百个范围执行此操作,您可能会看到一些性能下降。如果您的工作簿有许多相同的样式,最好先创建一个样式对象,应用所需的样式属性,为其命名,将其添加为命名样式。您可以使用 setStyleName 而不是 setStyle 来使用先前定义的样式对象。这样做意味着您不必为数百个不同的单元格范围单独提供数百个不同的样式对象,而只需在它们之间共享几个样式对象,从而显着提高内存和性能。// Example code for setting backcolor style from row 0 to row 10
let style = new GC.Spread.Sheets.Style();
style.backColor = "red"
for (let row = 0; row <= 100; row++) {
    for (let col = 0; col < sheet.getColumnCount(); col++) {
      sheet.setStyle(row, col, style.clone())
    }
}

// Using setStyleName it is more efficient
let style = new GC.Spread.Sheets.Style1();
style.name = "backColorStyle";
style.backColor = "red";
sheet.addNamedStyle("backColorStyle");
for (let row = 0; row<= 100;row++) {
    for (let col =0; col<sheet.getColumnCount(); col++) {
      sheet.setStyleName(row, col, "backColorStyle");
    }
}


11. 使用 SetArray 而不是 SetValue在 SpreadJS 中, setValue 方法允许您在单个单元格中设置值。但如果您将值设置到多个单元格中,使用 setArray 方法是更好的选择。 此方法允许您将指定的二维对象数组的值设置到工作表中特定的单元格区域。与对单元格范围内的每个单元格使用 setValue 相比,它可以通过限制所需的内存量来帮助提高性能。

您可以下载下面演示性能差异的示例项目,来实际对比性能优化效果
页: [1]
查看完整版本: 【常见问题】如何优化 SpreadJS 表格性能