1

显然,在 Excel Online 中发出请求时有 5MB 的限制(请参阅:https ://github.com/OfficeDev/office-js-docs-reference/issues/354 )。

我们正在使用 Office JavaScript API 将大量数据写入 Excel 工作表,使用以下代码:

// Example rows - in our actual code this comes from an API
const rows = [
  ["Date", "Product", "Sales", "Customers"],
  ["13/03/2020", "Chocolate biscuits", 598.00, 93],
  // ... and many more
]

sheet.getRangeByIndexes(0, 0, numRows, numColumns).values = rows;

超过上述限制将导致抛出此错误:RichApi.Error: An internal error has occurred.

构建时行数和列数是未知的;数据的大小取决于加载项用户运行的查询。

有什么可靠的方法可以确保我们的请求不超过限制?

我尝试跟踪 JSON 序列化值数组的大小,并允许一些开销因素:

Excel.run(async context => {
  const sheet = context.workbook.worksheets.add();

  // 50% of 5MB: allow 50% of overhead
  const THRESHOLD = 0.5 * (5 * 1000 * 1000);
  let bytes = 0;

  // Example rows - in our actual code this comes from an API
  const numColumns = 4;
  const rows = [
    ["Date", "Product", "Sales", "Customers"],
    ["13/03/2020", "Chocolate biscuits", 598.00, 93],
    // ... and many more
  ];

  for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
    const row = rows[rowIndex];
    sheet.getRangeByIndexes(rowIndex, 0, 1, numColumns).values = [row];
    bytes += JSON.stringify([row]).length;

    if (bytes >= THRESHOLD) {
      await context.sync();
      bytes = 0;
    }
  }

  return context.sync();
}

即使允许 50% 的开销,调用context.sync()仍然会抛出RichApi.Error: An internal error has occurred.一些数据。也许我可以将其设置为非常低的值(例如 10%),但在大多数情况下这将是非常低效的。我希望有一种更可靠的方法来计算有效负载大小,或者有一种方法可以询问 Office API 以检查待处理请求的大小。

4

1 回答 1

1

请求负载大小与以下因素成正比: - API 调用次数 - 对象数量(例如范围对象) - 要设置的值的长度

所以为了提高脚本的效率,需要优化API调用次数尽可能少。如果为每一行调用 Range.Values API,将会有更多的负载开销。

这里有一个带有优化 API 调用的示例供参考:

    const newValues = [
  ["Date", "Product", "Sales", "Customers"],
  ["13/03/2020", "Chocolate biscuits", 598.00, 93],
  // ... and many more
];

for (let rowIndex = 0; rowIndex < newValues.length;) {
  const row = newValues[rowIndex];
  var bytes = JSON.stringify([row]).length;
  var valuesToSet = [];
  valuesToSet.push(row);

  var rowCountForNextBatch = 1;
  for (; (rowIndex + rowCountForNextBatch) < newValues.length; rowCountForNextBatch++) {
    const nextRow = newValues[rowIndex + rowCountForNextBatch];
    bytes += JSON.stringify([nextRow]).length;

    if (bytes >= THRESHOLD) {
      break;
    }
    valuesToSet.push(nextRow);
  }

  console.log(valuesToSet);
  console.log(rowCountForNextBatch);
  sheet.getRangeByIndexes(rowIndex, 0, rowCountForNextBatch, numColumns).values = valuesToSet;
  await context.sync();

  rowIndex += rowCountForNextBatch;
} 
于 2020-04-16T13:01:33.500 回答