从模板复制数据验证时,Google Apps脚本中始终存在零星的内存错误

问题描述 投票:3回答:1

我有数百个由模板工作表制成的电子表格。它们的工作表,行,列等都具有相同的编号/名称...

我已经向模板添加了一些数据验证。我想将数据验证从模板复制到每个电子表格。我有代码,它可以工作,但是会引发内存错误。

它总是引发错误-唯一改变的是在引发错误之前它已经处理了多少个目标电子表格。有时它会在抛出错误之前处理4个电子表格,有时是50个,有时更多/更少。我不知道为什么。

我将代码精简为工作示例。我不能共享源文件,但它们只是5张纸/标签和各种数据验证的普通电子表格。如果重要的话,数据验证将使用命名范围。例如:=REGEXMATCH(LOWER(google_drive_url) , "^https:\/\/drive\.google\.com\/drive\/folders\/[a-z0-9_-]{33}$")

我已经评论了下面的代码,但这里有一个回顾:

  1. 获取模板电子表格并在其中缓存所有数据验证
  2. 浏览每个目标电子表格:
    1. 几乎所有数据验证
    2. 从模板应用数据验证

在我的真实代码中,我有一个目标文件ID数组。出于测试目的,我只使用一个目标文件,并多次应用模板中的数据验证。

function myFunction() {
  var sourceFileID = "1rB7Z0C615Kn9ncLykVhVAcjmwkYb5GpYWpzcJRjfcD8";
  var destinationFileID = "1SMrwTuknVa1Xky9NKgqwg16_JNSoHcFTZA6QxzDh7q4";

  // get the source file
  var sourceSpreadsheet = SpreadsheetApp.openById(sourceFileID);
  var sourceDataValidationCache = {};

  // go through each sheet and get a copy of the data validations
  // cache them for quick access later
  sourceSpreadsheet.getSheets().forEach(function(sourceSheet){
    var sheetName = sourceSheet.getName();

    // save all the data validations for this sheet
    var thisSheetDataValidationCache = [];

    // get the full sheet range
    // start at first row, first column, and end at max rows and max columns
    // get all the data validations in it
    // go through each data validation row
    sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns()).getDataValidations().forEach(function(row, rowIndex){
      // go through each column
      row.forEach(function(cell, columnIndex){
        // we only need to save if there is a data validation
        if(cell)
        {
          // save it
          thisSheetDataValidationCache.push({
            "row" : rowIndex + 1,
            "column" : columnIndex + 1,
            "dataValidation" : cell
          });
        }
      });
    });

    // save to cache for this sheet
    sourceDataValidationCache[sheetName] = thisSheetDataValidationCache;
  });

  // this is just an example
  // so just update the data validations in the same destination numerous times to show the memory leak
  for(var i = 0; i < 100; ++i)
  {
    // so we can see from the log how many were processed before it threw a memory error
    Logger.log(i);

    // get the destination
    var destinationSpreadsheet = SpreadsheetApp.openById(destinationFileID);

    // go through each sheet
    destinationSpreadsheet.getSheets().forEach(function(destinationSheet){
      var sheetName = destinationSheet.getName();

      // get the full range and clear existing data validations
      destinationSheet.getRange(1, 1, destinationSheet.getMaxRows(), destinationSheet.getMaxColumns()).clearDataValidations();

      // go through the cached data validations for this sheet
      sourceDataValidationCache[sheetName].forEach(function(dataValidationDetails){
        // get the cell/column this data validation is for
        // copy it, build it, and set it
        destinationSheet.getRange(dataValidationDetails.row, dataValidationDetails.column).setDataValidation(dataValidationDetails.dataValidation.copy().build());
      });
    });
  }
}

代码是否有问题?为什么会抛出内存不足错误?无论如何,有没有赶上/预防它?

google-apps-script google-sheets
1个回答
0
投票

为了更好地了解失败原因,我建议您对迭代进行计数,以了解正在经历的迭代次数。

我也刚刚注意到这条线

sourceSheet.getRange(1, 1, sourceSheet.getMaxRows(), sourceSheet.getMaxColumns()).getDataValidations().forEach(function(row, rowIndex){

这不是一个好主意,因为getMaxRows()getMaxColumns()将获得工作表中的总行数,而不是包含数据的行数,这意味着,如果您的工作表是100x100且仅前20x20有数据单元格,您将获得覆盖整个10,000个单元格的范围,然后调用forEach意味着您要遍历每个单元格。

一种更好的方法是使用getDataRange(),它将返回一个覆盖整个数据(Documentation)的范围。这样一来,您可以使用更小的范围和更少的单元来处理。

© www.soinside.com 2019 - 2024. All rights reserved.