脚本停止工作。我关闭了 sumbissions 并稍后重新启用。现在脚本又能用了,它对 google 来说是不是太密集了?
Script stopped working. I turned off sumbissions & re-enabled later. now script works again, is it too instensive for google?
我为 google 创建了一个在提交表单上运行的脚本。
它需要一个在表单中输入的数字,并在 sheet 中查找它。
如果找到匹配项,它会在提交表单中输入时间戳。
在这里
// this is the name of our script, myFunction can be anything.
// e is a special variable, its the form & answers that has
// just been submitted by a user.
function myFunction(e) {
var sessionDate = e.values[0]; // This gets the timestamp of the submission
var sessionID = e.values[1]; // This gets the session ID the user entered
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the spreadsheet where the form is attached to and all sheets are stored
var sheet = ss.getSheetByName("Data Dump"); // Specifies the data dump sheet, which has the IDs and the cell we want to add the timestamp to
var range = sheet.getRange("B:B"); // Specifies the column that holds the session IDs, in the data dump sheet
var values = range.getValues(); // Reads the data in the sessions ID column, that we specified earlier
for(i=0;i<values.length;i++){ // This goes through the session ids one by one, and we can test each one
if (values[i][0] == sessionID){ // This is the test. If the ID we are currently looking at matches the ID on the form response, then lets do something
sheet.getRange(i+1, 7).setValue(sessionDate); // This is us doing that something. Using where we found the matching ID, lets write the timestamp in a cell.
break; // This stops us going through anymore ID's as we have already found the one we are looking for
}
}
}
经过反复测试,效果很好。然后它被设置为上线。
与很多人分享的表格。
有很多提交,然后脚本停止运行。即使在手动测试时,我也没有遇到具体错误。 Just Spreadsheet 服务错误。
所以我在一两天前停止在表格上回复。今天是我不得不查看的第一个更改,一切正常。脚本在几秒钟内运行。
我唯一能想到的是脚本对于 google 来说太密集了,而且要进行多次提交,我特别考虑 for
循环可能会给它带来问题。
有没有人有任何想法或我可以尝试的任何事情?
提前致谢
而不是循环中的sheet.getRange(i+1, 7).setValue(sessionDate);
,放入range.offset(i, 7).setValue(sessionDate);
看这里:https://developers.google.com/apps-script/reference/spreadsheet/range#offsetrowoffset-columnoffset
但是,如果提交了多个表单,您可能会同时调用脚本,因此锁定脚本或节省时间或对表单进行排队可能会有所帮助。
使用锁(参见:https://developers.google.com/apps-script/reference/lock/lock#tryLock(Integer))
保存 time/queue 表格的更复杂的解决方案:
尝试完全不同的策略。
例如:不是在表单提交触发器时调用 myFunction(e)
,而是将所有到达 PropertiesService.getScriptProperties().setProperty
的 e.values
存储起来,同时创建一个定时触发器 运行 myFunction
一分钟,从 PropertiesService
中检索所有存储的 e.values
,然后将它们全部处理成一个块。同时,任何新的 e.Values
都将存储在 PropertiesService 中(参见 https://developers.google.com/apps-script/reference/script/clock-trigger-builder#after(Integer) )
我意识到这些不是简单的解决方案。如果您对它们感兴趣,我可以尝试帮助编写脚本。我不是专家,但我会尝试使用这些选项。
对于表单提交,您应该始终使用 LockService
。因为互联网可能连接不好,或者 Google 的服务器可能很慢,等等。你应该在获得锁时有一个 try/catch:
try {
var lock = LockService.getScriptLock();
var isLockt = lock.tryLock(10000);
catch (err) {
Utilities.sleep(2000);//Wait 2 seconds
lock = LockService.getScriptLock();//Try again
isLockt = lock.tryLock(10000);
};
if (!isLockt) { // Not true
//Email developer. There was an error
//Email user. There was an error.
//Keep running code? Or quit?
return;
};
您不需要遍历您的值。有一种更快的方法。您只会获得一列数据,因此不需要二维数组。取二维数组并将其展平为一维。
var values = range.getValues();
values = values.toString().split(",");//Convert 2D to 1D
var indexOfSessionID = values.indexOf(sessionID);//Gets index of first
//occurrence of the sessionID
这为您提供了数据中第一次出现 sessionID 的索引。数据是零索引的,因此索引和行号不同步。索引零是数组中的第一个元素。如果范围从第一行开始,则要获得正确的行号,请将索引加 1。如果范围从第二行开始,则添加 2。
如果有多个会话 ID,indexOf()
只会获取第一个。但是您的 for
循环在获取会话 ID 后中断,所以我假设没关系。
此外,我将更改此行:
var range = sheet.getRange("B:B");
收件人:
var range = sheet.getRange(1,2,sheet.getLastRow());
从第 1 行第 2 列开始,获取到最后一行的行数。
所以在经过大量思考和来自@David Tew 的一些改变游戏规则的指示之后,我认为这就是解决方案。
// this is the name of our script, myFunction can be anything. e is a special variable, its the form & answers that has just been submitted by a user.
function myFunction(e) {
var lock = LockService.getScriptLock();
lock.waitLock(10000);
var sessionDate = e.values[0]; // This gets the timestamp of the submission
var sessionID = e.values[1]; // This gets the session ID the user entered
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the spreadsheet where the form is attached to and all sheets are stored
var sheet = ss.getSheetByName("Data Dump"); // Specifies the data dump sheet, which has the IDs and the cell we want to add the timestamp to
var range = sheet.getRange(1, 2, sheet.getLastRow()); // Specifies the column that holds the session IDs, in the data dump sheet
var values = range.getValues(); // Reads the data in the sessions ID column, that we specified earlier
// Edits below
values = values.toString().split(","); //Convert 2D to 1D
var indexOfSessionID = values.indexOf(sessionID); //Gets index of first
//occurrence of the sessionID
if (indexOfSessionID > 0) {
sheet.getRange(indexOfSessionID + 1, 7).setValue(sessionDate);
}
SpreadsheetApp.flush();
lock.releaseLock();
}
我现在正在对多个用户进行测试。
Sandy - 感谢平面阵列的想法,但在对 David 发表评论时它已经让我印象深刻,但复制并粘贴代码。百胜。谢谢
虽然我已经逐行发布了我自己的问题的答案(我认为)。
我认为 David 向我指出的信息必须是最佳答案,因为它迫使我重新审视我制作的旧脚本并改变我将来使用事件驱动触发器的方式。这也很好地表明您正在努力解决自己的问题并避免投反对票。
我恳请任何编写具有事件驱动触发器(例如 onEdit、onFormsubmit)并且有多个用户触发该脚本的人阅读 link David 分享的内容。
编辑下方
4 个不同的 google 用户提交了 5 个回复,每个回复 2 分钟 10 秒,并且都有效。明天要做更大的测试。
我为 google 创建了一个在提交表单上运行的脚本。 它需要一个在表单中输入的数字,并在 sheet 中查找它。 如果找到匹配项,它会在提交表单中输入时间戳。
在这里
// this is the name of our script, myFunction can be anything.
// e is a special variable, its the form & answers that has
// just been submitted by a user.
function myFunction(e) {
var sessionDate = e.values[0]; // This gets the timestamp of the submission
var sessionID = e.values[1]; // This gets the session ID the user entered
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the spreadsheet where the form is attached to and all sheets are stored
var sheet = ss.getSheetByName("Data Dump"); // Specifies the data dump sheet, which has the IDs and the cell we want to add the timestamp to
var range = sheet.getRange("B:B"); // Specifies the column that holds the session IDs, in the data dump sheet
var values = range.getValues(); // Reads the data in the sessions ID column, that we specified earlier
for(i=0;i<values.length;i++){ // This goes through the session ids one by one, and we can test each one
if (values[i][0] == sessionID){ // This is the test. If the ID we are currently looking at matches the ID on the form response, then lets do something
sheet.getRange(i+1, 7).setValue(sessionDate); // This is us doing that something. Using where we found the matching ID, lets write the timestamp in a cell.
break; // This stops us going through anymore ID's as we have already found the one we are looking for
}
}
}
经过反复测试,效果很好。然后它被设置为上线。 与很多人分享的表格。
有很多提交,然后脚本停止运行。即使在手动测试时,我也没有遇到具体错误。 Just Spreadsheet 服务错误。
所以我在一两天前停止在表格上回复。今天是我不得不查看的第一个更改,一切正常。脚本在几秒钟内运行。
我唯一能想到的是脚本对于 google 来说太密集了,而且要进行多次提交,我特别考虑 for
循环可能会给它带来问题。
有没有人有任何想法或我可以尝试的任何事情?
提前致谢
而不是循环中的sheet.getRange(i+1, 7).setValue(sessionDate);
,放入range.offset(i, 7).setValue(sessionDate);
看这里:https://developers.google.com/apps-script/reference/spreadsheet/range#offsetrowoffset-columnoffset
但是,如果提交了多个表单,您可能会同时调用脚本,因此锁定脚本或节省时间或对表单进行排队可能会有所帮助。
使用锁(参见:https://developers.google.com/apps-script/reference/lock/lock#tryLock(Integer))
保存 time/queue 表格的更复杂的解决方案:
尝试完全不同的策略。
例如:不是在表单提交触发器时调用 myFunction(e)
,而是将所有到达 PropertiesService.getScriptProperties().setProperty
的 e.values
存储起来,同时创建一个定时触发器 运行 myFunction
一分钟,从 PropertiesService
中检索所有存储的 e.values
,然后将它们全部处理成一个块。同时,任何新的 e.Values
都将存储在 PropertiesService 中(参见 https://developers.google.com/apps-script/reference/script/clock-trigger-builder#after(Integer) )
我意识到这些不是简单的解决方案。如果您对它们感兴趣,我可以尝试帮助编写脚本。我不是专家,但我会尝试使用这些选项。
对于表单提交,您应该始终使用 LockService
。因为互联网可能连接不好,或者 Google 的服务器可能很慢,等等。你应该在获得锁时有一个 try/catch:
try {
var lock = LockService.getScriptLock();
var isLockt = lock.tryLock(10000);
catch (err) {
Utilities.sleep(2000);//Wait 2 seconds
lock = LockService.getScriptLock();//Try again
isLockt = lock.tryLock(10000);
};
if (!isLockt) { // Not true
//Email developer. There was an error
//Email user. There was an error.
//Keep running code? Or quit?
return;
};
您不需要遍历您的值。有一种更快的方法。您只会获得一列数据,因此不需要二维数组。取二维数组并将其展平为一维。
var values = range.getValues();
values = values.toString().split(",");//Convert 2D to 1D
var indexOfSessionID = values.indexOf(sessionID);//Gets index of first
//occurrence of the sessionID
这为您提供了数据中第一次出现 sessionID 的索引。数据是零索引的,因此索引和行号不同步。索引零是数组中的第一个元素。如果范围从第一行开始,则要获得正确的行号,请将索引加 1。如果范围从第二行开始,则添加 2。
如果有多个会话 ID,indexOf()
只会获取第一个。但是您的 for
循环在获取会话 ID 后中断,所以我假设没关系。
此外,我将更改此行:
var range = sheet.getRange("B:B");
收件人:
var range = sheet.getRange(1,2,sheet.getLastRow());
从第 1 行第 2 列开始,获取到最后一行的行数。
所以在经过大量思考和来自@David Tew 的一些改变游戏规则的指示之后,我认为这就是解决方案。
// this is the name of our script, myFunction can be anything. e is a special variable, its the form & answers that has just been submitted by a user.
function myFunction(e) {
var lock = LockService.getScriptLock();
lock.waitLock(10000);
var sessionDate = e.values[0]; // This gets the timestamp of the submission
var sessionID = e.values[1]; // This gets the session ID the user entered
var ss = SpreadsheetApp.getActiveSpreadsheet(); // Gets the spreadsheet where the form is attached to and all sheets are stored
var sheet = ss.getSheetByName("Data Dump"); // Specifies the data dump sheet, which has the IDs and the cell we want to add the timestamp to
var range = sheet.getRange(1, 2, sheet.getLastRow()); // Specifies the column that holds the session IDs, in the data dump sheet
var values = range.getValues(); // Reads the data in the sessions ID column, that we specified earlier
// Edits below
values = values.toString().split(","); //Convert 2D to 1D
var indexOfSessionID = values.indexOf(sessionID); //Gets index of first
//occurrence of the sessionID
if (indexOfSessionID > 0) {
sheet.getRange(indexOfSessionID + 1, 7).setValue(sessionDate);
}
SpreadsheetApp.flush();
lock.releaseLock();
}
我现在正在对多个用户进行测试。 Sandy - 感谢平面阵列的想法,但在对 David 发表评论时它已经让我印象深刻,但复制并粘贴代码。百胜。谢谢
虽然我已经逐行发布了我自己的问题的答案(我认为)。 我认为 David 向我指出的信息必须是最佳答案,因为它迫使我重新审视我制作的旧脚本并改变我将来使用事件驱动触发器的方式。这也很好地表明您正在努力解决自己的问题并避免投反对票。
我恳请任何编写具有事件驱动触发器(例如 onEdit、onFormsubmit)并且有多个用户触发该脚本的人阅读 link David 分享的内容。
编辑下方
4 个不同的 google 用户提交了 5 个回复,每个回复 2 分钟 10 秒,并且都有效。明天要做更大的测试。