【问题标题】:Google app script exceeded execution time limit谷歌应用脚​​本超出执行时间限制
【发布时间】:2020-10-24 16:12:11
【问题描述】:

我有一个包含近 160 个子工作表的 Google 工作表。所有问题都在“全部”表中,B 列是它们应该在的实际电子表格名称。以下代码正在从“所有”电子表格中读取数据,并将它们完美地发送到所需电子表格的最后一行,但这需要很长时间!可能是因为它有很多子表并且一次又一次地使用 getSheetByName。现在,我将所有子工作表的名称和 ID 一次存储在“工作表”和“工作表 ID”数组中。我正在考虑比较rangeValues[j][1]sheetNames[k][0]。下面是电子表格的代码和截图。

这是合适的方式吗?请帮助我更快地运行脚本!

var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("All");
var rangeData = sheet.getDataRange();
var lastRow = rangeData.getLastRow();
var searchRange = sheet.getRange(1,1, lastRow, 8);
var curr_sheet;

function send() {
  var rangeValues = searchRange.getValues();
  var sheetNames = new Array();
  var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  for (var i=0 ; i<sheets.length ; i++) sheetNames.push( [ sheets[i].getName() ] );
  //Logger.log (sheetNames.length);
  
  var sheetID = new Array();
  var sheetIDs = SpreadsheetApp.getActiveSpreadsheet().getSheets();
  for (var i=0 ; i<sheetIDs.length ; i++) sheetID.push( [ sheetIDs[i].getSheetId() ] );
  //Logger.log (sheetID.length);

  for ( j = 0 ; j < lastRow; j++)
  {
      for ( k = 0 ; k < sheetNames.length ; k++) //
        {
          if (rangeValues[j][1] === sheetNames[k][0])
            {
              
              var targetSheet = ss.getSheetByName(sheetNames[k][0]); // This line is working but taking very long to complete
              var targetSheet = ss.getSheetByID(sheetIDs[k][0]); // This line is not code just to show what I'm thinking to do.
              
              targetSheet.getRange(targetSheet.getLastRow()+1, 1, 1, 8).setValues([rangeValues[j]]);
            }
         }
   }
}

【问题讨论】:

    标签: javascript for-loop google-apps-script optimization google-sheets


    【解决方案1】:

    我相信你的目标如下。

    • 您希望降低脚本的处理成本。

    修改点:

    • 类电子表格中没有getSheetByID 的方法。这样,我认为在您的情况下,可以删除以下脚本。

        var sheetID = new Array();
        var sheetIDs = SpreadsheetApp.getActiveSpreadsheet().getSheets();
        for (var i=0 ; i<sheetIDs.length ; i++) sheetID.push( [ sheetIDs[i].getSheetId() ] );
      
    • 在您的脚本中,getSheetByNamegetRange(###).setValues(###) 在循环中使用。而且,即使工作表是同一张工作表,每一行都使用setValues 在每一行的循环中放置。在这种情况下,处理成本会很高。我认为这些情况可能是您的问题的原因。

    • 幸运的是,在您的情况下,所有工作表都在同一个电子表格中。因此,为了降低脚本的处理成本,在这里,我想建议使用 Sheets API 将值放入每个工作表。修改脚本的流程如下。

      1. 检索电子表格和值。
        • 此脚本来自您的脚本。
      2. 检索电子表格中的所有工作表。
      3. 检查“B”列中的工作表名称是否存在。
      4. 使用 Sheets API 创建用于放置到每个工作表的对象。
      5. 使用创建的对象请求 Sheets API 的电子表格.values.batchUpdate 方法。

    当以上几点反映到你的脚本中时,它变成如下。

    修改脚本:

    请复制并粘贴以下脚本。还有,please enable Sheets API at Advanced Google services。然后,请运行脚本。

    function send() {
      // 1. Retrieve Spreadsheet and values. This script is from your script.
      var ss = SpreadsheetApp.getActiveSpreadsheet();
      var sheet = ss.getSheetByName("All");
      var rangeData = sheet.getDataRange();
      var lastRow = rangeData.getLastRow();
      var searchRange = sheet.getRange(1,1, lastRow, 8);
      var curr_sheet;
      var rangeValues = searchRange.getValues();
      
      // 2. Retrieve all sheets in the Spreadsheet.
      var sheets = ss.getSheets().reduce((o, e) => Object.assign(o, {[e.getSheetName()]: e}), {});
      
      // 3. Check whether the sheet names from the column "B" are existing.
      // 4. Create the object for putting to each sheet using Sheets API.
      var data = rangeValues.reduce((o, e) => {
        if (sheets[e[1]]) {
          if (o[e[1]]) {
            o[e[1]].values.push(e);
          } else {
            o[e[1]] = {range: `'${e[1]}'!A${sheets[e[1]].getLastRow() + 1}`, values: [e]};
          }
        }
        return o;
      }, {});
      
      // 5. Request the method of spreadsheets.values.batchUpdate of Sheets API using the created object.
      Sheets.Spreadsheets.Values.batchUpdate({data: Object.values(data), valueInputOption: "USER_ENTERED"}, ss.getId());
    }
    

    注意:

    • 在这种情况下,当您运行脚本时,将使用一个 API 调用。因为使用了电子表格.values.batchUpdate的方法。
    • 在我的环境中,当我使用示例电子表格测试上述脚本和您的脚本时,我可以确认您的脚本减少了大约 70% 的流程成本。

    参考资料:

    【讨论】:

    • 我不明白你做了什么,但它工作得很好,而不是 70,可能它减少了 90% 的流程成本!你是我的天使。
    • @Imtiaz 感谢您的回复。我很高兴你的问题得到了解决。有 2 点可以根据您的情况降低流程成本。 1. 将每一行放在同一张纸上时,通过汇总到一个值来放置这些值。 2. 将值放入每张表时,通过一次 API 调用将值放入每张表中。为了实现这一点,我建议使用 Sheets API。
    【解决方案2】:

    试试这个:

    应该会快很多

    function send() {
      var ss=SpreadsheetApp.getActive();
      var sh=ss.getSheetByName("All");
      var rg=sh.getRange(1,1,sh.getLastRow(),8);
      var v=rg.getValues();
      var names=[];
      var sheets=ss.getSheets();
      sheets.forEach(function(sh,i){names.push(sh.getName());});
      v.forEach(function(r){
        let idx=names.indexOf(r[1]);//column2
        if(idx!=-1) {
          sheets[idx].getRange(sheets[idx].getLastRow()+1,1,1,8).setValues([r]);
        }   
      });
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多