Google Apps Script运行缓慢致Google Form异常问题求助
解决Google Form测验生成时的访问冲突与不完整问题
一、核心问题根源
你的脚本直接修改现有表单:先清空所有题目,再逐个添加新题。这个过程中若有用户访问或提交,就会出现题目不全、分数异常、作答被清空的情况。同时脚本多次调用getRange导致运行效率低下,延长了生成时间,进一步加剧了问题。
二、分步解决方案
1. 表单状态管控:生成前禁用访问,完成后恢复
在脚本启动时将表单设为不接受响应,生成完成后再重新开放。用户在生成过程中访问会看到明确提示,无法进入作答流程。
修改createQuiz函数:
function createQuiz() { const form = FormApp.openById([formID]); // 先禁用表单响应,阻止用户访问 form.setAcceptingResponses(false); form.setCustomClosedFormMessage("测验正在更新,请稍后再试。"); // ---------------------- 原有生成逻辑开始 ---------------------- const file = SpreadsheetApp.openById([sheetID]); const sheet = file.getSheetByName("Questions"); // 一次性读取所有数据到内存,避免重复调用getRange const values = sheet.getDataRange().getValues(); const question_total = sheet.getLastRow() - 1; const question_req = 20; const index = questions(question_total, question_req); // 清空现有题目 const items = form.getItems(); while(items.length > 0){ form.deleteItem(items.pop()); } form.setIsQuiz(true); // 从内存数组中提取题目数据,不再调用getRange for(let r=0; r<question_req; r++) { const rowIndex = index[r]; // values第一行是表头,直接用索引取值 const title = values[rowIndex][0]; const nchoices = values[rowIndex][1]; const choices = [values[rowIndex][2], values[rowIndex][3], values[rowIndex][4], values[rowIndex][5]]; const feedback = values[rowIndex][6]; createShuffledChoices(form, title, nchoices, choices, feedback) } // ---------------------- 原有生成逻辑结束 ---------------------- // 生成完成后重新开放表单 form.setAcceptingResponses(true); }
2. 优化脚本性能,缩短生成时间
原脚本循环中多次调用getRange是Google Apps Script的性能瓶颈,改成一次性读取所有数据到内存数组,直接从数组提取信息,能大幅减少运行时间,降低用户在生成过程中访问的概率。
3. 防止并发触发:用锁机制避免多实例冲突
添加脚本锁,确保同一时间只有一个脚本实例在运行,彻底避免多个用户触发脚本导致的表单冲突:
在createQuiz开头补充锁逻辑:
function createQuiz() { // 获取脚本锁,超时30秒(可根据实际调整) const lock = LockService.getScriptLock(); if (!lock.tryLock(30000)) { // 获取锁失败,说明已有实例在运行,直接退出 console.log("测验正在生成中,请稍后再试"); return; } const form = FormApp.openById([formID]); form.setAcceptingResponses(false); form.setCustomClosedFormMessage("测验正在更新,请稍后再试。"); // ... 原有生成逻辑 ... form.setAcceptingResponses(true); // 释放锁 lock.releaseLock(); }
三、辅助优化:随机索引生成算法
原questions函数效率较低,改用Fisher-Yates洗牌算法生成随机索引,避免循环等待:
function questions(question_total, question_req) { // 生成1到question_total的索引数组 const indices = Array.from({length: question_total}, (_, i) => i + 1); // Fisher-Yates洗牌 for (let i = indices.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [indices[i], indices[j]] = [indices[j], indices[i]]; } // 返回前question_req个随机索引 return indices.slice(0, question_req); }
四、效果验证
修改后:
- 脚本运行时,用户访问表单会看到自定义关闭提示,无法进入作答
- 脚本运行时间大幅缩短,减少冲突窗口
- 锁机制确保不会有多个脚本实例同时修改表单,彻底解决作答被清空的问题
内容的提问来源于stack exchange,提问作者JCHI
相关产品推荐
相关产品推荐

