google-apps-script - 通过 Google App Script 获取 XML 在 Exceeded maximum execution time 时结束
问题描述
我正在尝试通过 Google App Script 获取 XML,然后将这些值传递给 Google Sheets。几次迭代后一切正常。如果我尝试更多,我将超过最大执行时间。
下面的代码会导致错误消息“超过最大执行时间”。如果我降低迭代次数(3),它将起作用。但我需要遍历大约 20K 行。
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>
任何建议,可能有什么问题?
非常感谢
解决方案
正如您收到的错误所说,您已达到脚本执行时间限制,根据您的帐户类型,可能为 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
(在连续执行中,脚本知道在哪里恢复循环。例如,如果您不知道如何存储和检索脚本属性,请参阅此答案。
示例代码(检查内联注释):
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();
}
}
参考:
推荐阅读
- amazon-web-services - Python Boto3 S3桶加密结果为0字节文件
- angular - Angular 5 通过组件传递 ngModel
- vb.net - 来自多个句柄的 Sender.Gettype
- windows - Windows 2016 上的 Traefik 无法连接到 Docker
- python - python 正则表达式在下划线内查找任何字母或单词
- r - 监控在我的内部网络中共享的闪亮应用程序
- reactjs - 如何在反应应用程序中要求/导入 chartist-plugin-tooltip
- python - Python:字符串比较
- amazon-web-services - 为什么我被拒绝访问来自 aws s3 存储桶的资产?
- python - 使用动态命名导出多个 csv 文件