Apps Script脚本执行超时求助(附修改后代码)
本人仅为C++入门水平,正在为Google Sheets编写一个简单的Apps Script脚本,但执行时出现超时情况。仅修改了模板中Task 3的for循环部分,可能还有字符串拼接的问题,由于不熟悉Java语法,可能忽略了明显错误。附上脚本代码如下:
function routineActivator() { /** Task 1) Open the Event Calendar. **/ var spreadsheet = SpreadsheetApp.getActiveSheet(); var calendarId = 'myEmail'; var eventCal = CalendarApp.getCalendarById(calendarId); /** Task 2) Pull each shift information into the code, in a form that the code can understand. **/ var routine = spreadsheet.getRange('A4:D74').getValues(); /** Task 3) Do the work! **/ for (x=0; x<routine.length; x++) { var task = routine[x]; var des = task[3] if(des=1){ var label = task[2]; var startTime = task[0] + task[1]; while (des != 2){ var endTime = task[0] + task[1]; task++; } eventCal.createEvent(label, startTime, endTime); } } /** Task 4) Make it easy to use. **/ function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('Sync to Calendar') .addItem('Schedule tasks now', 'routineActivator') } }
尝试运行时出现无限循环并超时,请求帮忙排查问题原因。
问题原因及修正方案
1. 无限循环的核心问题
你的while (des != 2)循环里,从未修改过des的值,而且task++是对数组元素做自增操作,完全不影响des变量。这导致这个while循环永远不会退出,直接触发脚本超时。
2. 赋值操作代替了比较判断
if(des=1)这里是赋值语句,不是判断相等。每次执行都会把des设为1,条件永远为真,所有行都会进入这个分支,放大了无限循环的影响。应该改为if(des === 1)(严格相等)或者if(des == 1)。
3. 时间格式错误
task[0] + task[1]是把日期和时间直接字符串拼接,CalendarApp无法识别这种格式的字符串作为时间参数。需要把拼接后的字符串转为Date对象,比如:
var startTime = new Date(task[0] + " " + task[1]);
4. 嵌套函数无效
onOpen()被定义在routineActivator()内部,Google Sheets无法在打开文档时触发这个函数。需要把onOpen()移到全局作用域,和routineActivator()同级。
5. 未声明的全局变量
for (x=0; x<routine.length; x++)里的x没有用var/let声明,会成为全局变量,可能引发意外的副作用,建议改为for (let x=0; x<routine.length; x++)。
修正后的示例代码
function routineActivator() { /** Task 1) Open the Event Calendar. **/ var spreadsheet = SpreadsheetApp.getActiveSheet(); var calendarId = 'myEmail'; var eventCal = CalendarApp.getCalendarById(calendarId); /** Task 2) Pull shift information **/ var routine = spreadsheet.getRange('A4:D74').getValues(); /** Task 3) Process shifts **/ for (let x=0; x<routine.length; x++) { var task = routine[x]; var des = task[3]; if(des === 1){ var label = task[2]; // 正确转换为Date对象 var startTime = new Date(task[0] + " " + task[1]); // 假设需要匹配当前行之后的des=2行作为结束时间 let endTime; for (let y = x; y < routine.length; y++) { if (routine[y][3] === 2) { endTime = new Date(routine[y][0] + " " + routine[y][1]); break; } } if (endTime) { eventCal.createEvent(label, startTime, endTime); } } } } /** Task 4) Add menu on open **/ function onOpen() { var ui = SpreadsheetApp.getUi(); ui.createMenu('Sync to Calendar') .addItem('Schedule tasks now', 'routineActivator') .addToUi(); }
注:修正后的代码里,针对endTime的获取做了简单调整(假设你需要找当前des=1行之后的des=2行作为结束时间),你可以根据实际需求修改这部分逻辑。
内容的提问来源于stack exchange,提问作者mattgreenhough

