如何使用 FormApp...getResponses() 减少脚本执行时间?
How to reduce time of script execution with FormApp...getResponses()?
表单内置的Email收集功能为Text格式。我们有很多员工填写这个表格,所以从下拉列表中选择比手动输入每个员工的电子邮件更方便。内置的邮件收集功能不允许使用下拉列表问题类型,所以我不得不禁用它并使用脚本将响应发送到电子邮件。
此外,当您select表格中的选项之一(传输)时,您需要插入一个额外的带有数据的更正行。这也是脚本完成的。
脚本运行良好,但不幸的是,它的执行时间达到了 45 秒。我认为这是异常大的。
更新代码:
var FORM_ID = '#####';
var SHEET_NAME = 'Operations';
function sendFormToEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
console.time('section10'); // 25579ms
var sheet = ss.getSheetByName(SHEET_NAME);
console.timeEnd('section10');
// Open a form by ID and log the responses to each question.
var form = FormApp.openById(FORM_ID);
var formResponses = form.getResponses();
var i = formResponses.length - 1;
var formResponse = formResponses[i]; // Last item
var itemResponses = formResponse.getItemResponses();
var length = itemResponses.length;
Logger.log("length = " + length);
var emailTo = itemResponses[0].getResponse(); // Returns the email if given
var cp = itemResponses[1].getResponse(); // Counterparty
var subject = "Input form: "+ cp;
var datePay = itemResponses[2].getResponse(); // Date of the operation
var dateAccept = itemResponses[3].getResponse(); // Date of acceptance
var sum = itemResponses[4].getResponse() ; // Amount
var what = itemResponses[5].getResponse(); // Operation type
var comm = "Correction " + itemResponses[length - 1].getResponse(); // Last response
var sum_1 = parseFloat(sum.replace(/,/, '.')) * (-1); // Amount * (-1)
var timestamp = new Date();
var textBody = "Operation: " + timestamp + ";\n";
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
var resp = itemResponse.getResponse();
textBody += itemResponse.getItem().getTitle() + "=" + resp + ";\n";
}
if (what == 'Transfer') { // If the transfer between your accounts
var lr = sheet.getLastRow();
sheet.insertRowBefore(lr);
var values = [datePay, dateAccept, "", sum_1, "", "", "", "", comm, "", "", "", what, timestamp, "", "", ""];
Logger.log(values);
console.time('section12'); // 19449ms
sheet.getRange(lr, 2, 1, 17).setValues([values]);
console.timeEnd('section12')
}
if(emailTo !== undefined){
GmailApp.sendEmail(emailTo, subject, textBody);
}
}
一开始以为是验收的大尺寸sheet(约13000行)。我创建了一份table,减少了几十行,但是速度并没有增加多少。
然后我从表单中删除了答案(只有不到 9000 个)- 同样的事情,我没有获得太多性能提升。
有人知道如何更改脚本算法以提高其性能吗?
===
结论
感谢@TheMaster 对 console.time()
的帮助。多亏了这个工具,我发现了代码中的瓶颈。更准确地说,代码运行良好,但它与代码交互的 spreadsheets 系统的结构有关。结构有待优化。
还有一个想法可能是针对 Google 开发人员的。如果有一个工具可以直观地(图形化地)显示构成单个系统的 spreadsheet 和 sheet 之间的关系,那就太好了。也许具有某种反映其块之间交互时间的数字特征。这样可以快速消除系统中的此类瓶颈并对其进行改进。
调查:
- 使用每个代码部分的
console.time()
和 console.timeEnd()
并计算到达每个代码部分所花费的时间来确定问题。
问题:
如 中所述,这是由于膨胀的传播 sheet 和许多 sheet 和导入公式所致。这导致需要更多时间来获得准确的 sheet 并使用 setValues:
console.time('section10'); // 25579ms
var sheet = ss.getSheetByName(SHEET_NAME);
console.timeEnd('section10');
//....
console.time('section12'); // 19449ms
sheet.getRange(lr, 2, 1, 17).setValues([values]);
console.timeEnd('section12')
可能的解决方案:
- 减少 sheet 的数量
- 减少相互关联的传播sheets (=
import*
公式)
- 删除底部的空行和每个右侧的空列sheet。
表单内置的Email收集功能为Text格式。我们有很多员工填写这个表格,所以从下拉列表中选择比手动输入每个员工的电子邮件更方便。内置的邮件收集功能不允许使用下拉列表问题类型,所以我不得不禁用它并使用脚本将响应发送到电子邮件。
此外,当您select表格中的选项之一(传输)时,您需要插入一个额外的带有数据的更正行。这也是脚本完成的。
脚本运行良好,但不幸的是,它的执行时间达到了 45 秒。我认为这是异常大的。
更新代码:
var FORM_ID = '#####';
var SHEET_NAME = 'Operations';
function sendFormToEmail() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
console.time('section10'); // 25579ms
var sheet = ss.getSheetByName(SHEET_NAME);
console.timeEnd('section10');
// Open a form by ID and log the responses to each question.
var form = FormApp.openById(FORM_ID);
var formResponses = form.getResponses();
var i = formResponses.length - 1;
var formResponse = formResponses[i]; // Last item
var itemResponses = formResponse.getItemResponses();
var length = itemResponses.length;
Logger.log("length = " + length);
var emailTo = itemResponses[0].getResponse(); // Returns the email if given
var cp = itemResponses[1].getResponse(); // Counterparty
var subject = "Input form: "+ cp;
var datePay = itemResponses[2].getResponse(); // Date of the operation
var dateAccept = itemResponses[3].getResponse(); // Date of acceptance
var sum = itemResponses[4].getResponse() ; // Amount
var what = itemResponses[5].getResponse(); // Operation type
var comm = "Correction " + itemResponses[length - 1].getResponse(); // Last response
var sum_1 = parseFloat(sum.replace(/,/, '.')) * (-1); // Amount * (-1)
var timestamp = new Date();
var textBody = "Operation: " + timestamp + ";\n";
for (var j = 0; j < itemResponses.length; j++) {
var itemResponse = itemResponses[j];
var resp = itemResponse.getResponse();
textBody += itemResponse.getItem().getTitle() + "=" + resp + ";\n";
}
if (what == 'Transfer') { // If the transfer between your accounts
var lr = sheet.getLastRow();
sheet.insertRowBefore(lr);
var values = [datePay, dateAccept, "", sum_1, "", "", "", "", comm, "", "", "", what, timestamp, "", "", ""];
Logger.log(values);
console.time('section12'); // 19449ms
sheet.getRange(lr, 2, 1, 17).setValues([values]);
console.timeEnd('section12')
}
if(emailTo !== undefined){
GmailApp.sendEmail(emailTo, subject, textBody);
}
}
一开始以为是验收的大尺寸sheet(约13000行)。我创建了一份table,减少了几十行,但是速度并没有增加多少。 然后我从表单中删除了答案(只有不到 9000 个)- 同样的事情,我没有获得太多性能提升。
有人知道如何更改脚本算法以提高其性能吗?
===
结论
感谢@TheMaster 对 console.time()
的帮助。多亏了这个工具,我发现了代码中的瓶颈。更准确地说,代码运行良好,但它与代码交互的 spreadsheets 系统的结构有关。结构有待优化。
还有一个想法可能是针对 Google 开发人员的。如果有一个工具可以直观地(图形化地)显示构成单个系统的 spreadsheet 和 sheet 之间的关系,那就太好了。也许具有某种反映其块之间交互时间的数字特征。这样可以快速消除系统中的此类瓶颈并对其进行改进。
调查:
- 使用每个代码部分的
console.time()
和console.timeEnd()
并计算到达每个代码部分所花费的时间来确定问题。
问题:
如
console.time('section10'); // 25579ms
var sheet = ss.getSheetByName(SHEET_NAME);
console.timeEnd('section10');
//....
console.time('section12'); // 19449ms
sheet.getRange(lr, 2, 1, 17).setValues([values]);
console.timeEnd('section12')
可能的解决方案:
- 减少 sheet 的数量
- 减少相互关联的传播sheets (=
import*
公式) - 删除底部的空行和每个右侧的空列sheet。