通过Google App脚本提取XML超出了最大执行时间

时间:2020-03-18 10:34:37

标签: google-apps-script

我正在尝试通过Google App脚本获取XML,然后将这些值传递给Google表格。几次迭代后一切正常。如果我尝试更多,将超出最长执行时间。

下面的代码导致错误消息“超出最大执行时间”。如果降低迭代次数(3),它将起作用。但是我需要遍历大约2万行。

function myFunction(){
  var url = '<<file name>>';
  var bggXml = UrlFetchApp.fetch(url).getContentText();

  var document = XmlService.parse(bggXml);
  var root = document.getRootElement();
  var now = new Date();



  for(var i = 0; i <= 20; i++){


  var shopitem = root.getChildren('SHOPITEM')[i];

  var code = shopitem.getChild('CODE').getText();
  var stock100 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[0].getChild('VALUE').getText();
  var stock801 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[1].getChild('VALUE').getText();




  SpreadsheetApp.getActiveSheet().getRange(1+i,1).setValue(code);
  SpreadsheetApp.getActiveSheet().getRange(1+i,2).setValue(stock100);
  SpreadsheetApp.getActiveSheet().getRange(1+i,3).setValue(stock801);


 } 


}

饲料结构

<SHOP>
    <SHOPITEM>
        <CODE>#SKU#</CODE>
        <STOCK>
            <WAREHOUSES>
                <WAREHOUSE>
                    <NAME>Sklad 100</NAME>
                    <VALUE>"stock value"</VALUE>
                </WAREHOUSE>
                <WAREHOUSE>
                    <NAME>Sklad 801</NAME>
                    <VALUE>"stock value"</VALUE>
                </WAREHOUSE>
            </WAREHOUSES>
        </STOCK>
    </SHOPITEM>
</SHOP>

任何建议,可能是什么问题?

非常感谢您

1 个答案:

答案 0 :(得分:0)

正如您所得到的错误所言,您已达到脚本执行时间限制,具体取决于here,具体取决于帐户类型,该时间可能为6或30分钟。

为避免这种情况,您可以做两件事(不互斥):

提高代码效率:

提高代码效率。例如,您可以将一个单独的setValue替换为一个setValues。您将不得不替换它:

SpreadsheetApp.getActiveSheet().getRange(1+i,1).setValue(code);
SpreadsheetApp.getActiveSheet().getRange(1+i,2).setValue(stock100);
SpreadsheetApp.getActiveSheet().getRange(1+i,3).setValue(stock801);

与此:

SpreadsheetApp.getActiveSheet().getRange(1+i, 1, 1, 3).setValues([[code, stock100, stock801]]);

将脚本拆分为多个执行:

您还可以通过设置基于时间的触发器将循环分成不同的执行,该触发器将在前一个执行完成后触发每个后续执行。您将必须执行以下操作:

  • 找出在达到时间限制之前可以进行的迭代次数(在下面的示例中,该次数设置为3)。每个执行都必须在完成之前进行这种迭代。

  • 在函数结尾创建以下基于时间的触发器:after(durationMilliseconds)。因此,您可以在指定的毫秒数后运行指定的任何功能。每次执行后,都会创建一个触发器来触发下一个触发器。

  • 由于要拆分循环,因此必须将循环计数器(i)存储在某个位置(可以在每次执行结束时使用PropertiesService或将其写入电子表格),并在下一个开始处进行检索,这样,在每次连续执行时,脚本都知道在哪里恢复循环。例如,如果您不知道如何存储和检索脚本属性,请参见this answer

示例代码(检查内联注释):

function myFunction(){
  var i_old = // Retrieve i stored in previous execution (from PropertiesService? Spreadsheet?) (should be 0 if first execution)
  var n_int = 3 // Number of iterations that can be done in a single execution without reaching time limit (change accordingly)
  var total = 20 // Total number of iterations (change accordingly)
  var url = '<<file name>>';
  var bggXml = UrlFetchApp.fetch(url).getContentText();
  var document = XmlService.parse(bggXml);
  var root = document.getRootElement();
  var now = new Date();
  // Loop starts at previous i store until it reaches the specified number of iterations for one execution or reaches the total number:
  for(var i = i_old; i <= i_old + n_int && i <= total; i++) { 
    var shopitem = root.getChildren('SHOPITEM')[i];
    var code = shopitem.getChild('CODE').getText();
    var stock100 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[0].getChild('VALUE').getText();
    var stock801 = shopitem.getChild('STOCK').getChild('WAREHOUSES').getChildren('WAREHOUSE')[1].getChild('VALUE').getText();
    SpreadsheetApp.getActiveSheet().getRange(1 + i, 1, 1, 3).setValues([[code, stock100, stock801]]);
  }
  // Store i somewhere (PropertiesService? Spreadsheet?)
  if (i <= total) { // Create trigger if i hasn't reach the total number of iteration
    ScriptApp.newTrigger("myFunction")
    .timeBased()
    .after(1000 * 60) // This fires the function 1 minute after the current execution ends. Change this time according to your preferences
    .create();  
  }
}

参考: