如何优化Google Apps Script提升电子表格脚本运行速度?
Google Apps Script 代码优化建议(针对Google Sheets)
你的代码运行慢的核心原因是频繁调用Spreadsheet服务——循环里反复执行getRange()、copyTo()、getValue()这些操作,每次都要和Google服务器通信,累积起来就会拖慢速度。下面是具体的优化方案和重构后的代码:
核心优化方向
- 一次性批量读取所有需要的数据到内存数组,后续操作全在内存中完成,大幅减少服务器交互次数
- 用数组收集目标行数据,最后一次性写入工作表,替代逐行复制
- 在内存中完成空标题/副标题的过滤,避免反复删除、插入行的低效操作
- 用映射表替代公式匹配逻辑,省去临时列的读写开销
重构后的完整代码
function allToMaster() { const sss = SpreadsheetApp.getActive(); const ssAll = sss.getSheetByName("FF All"); const ssMaster = sss.getSheetByName("FF Master"); const ssSetup = sss.getSheetByName("FF Setup"); // 1. 批量读取所有数据到内存,避免反复调用Spreadsheet服务 const allData = ssAll.getDataRange().getValues(); const allBackgrounds = ssAll.getDataRange().getBackgrounds(); const setupB = ssSetup.getRange("B:B").getValues().flat(); const setupC = ssSetup.getRange("C:C").getValues().flat(); // 构建勾选状态映射表,替代原公式匹配逻辑 const setupMap = new Map(); setupC.forEach((val, idx) => { if (val) setupMap.set(val, setupB[idx] === true); }); // 2. 收集需要写入Master的行数据(包含背景色标记) const masterRows = []; const tallRowIndices = []; // 记录需要设置136行高的行号(数组索引+1) // 先加入表头 masterRows.push({ data: allData[0], bg: allBackgrounds[0][0] }); // 处理FF All的每一行(从第2行开始,数组索引1) for (let i = 1; i < allData.length; i++) { const currentBg = allBackgrounds[i][0]; const currentRow = allData[i]; if (currentBg === "#a8d08d" || currentBg === "#e2efd9") { masterRows.push({ data: currentRow, bg: currentBg }); } else { const matchVal = currentRow[1]; // B列的值,用于匹配FF Setup if (setupMap.get(matchVal)) { masterRows.push({ data: currentRow, bg: currentBg }); tallRowIndices.push(masterRows.length); // 记录当前行在Master中的位置(行号) } } } // 3. 内存中清理空标题/副标题 const cleanedRows = []; for (let i = 0; i < masterRows.length; i++) { const current = masterRows[i]; const next = masterRows[i + 1]; if (current.bg === "#e2efd9") { // 副标题:下一行不是标题/副标题才保留 if (!next || !(next.bg === "#e2efd9" || next.bg === "#a8d08d")) { cleanedRows.push(current.data); } } else if (current.bg === "#a8d08d") { // 标题:下一行不是标题才保留 if (!next || next.bg !== "#a8d08d") { cleanedRows.push(current.data); } } else { cleanedRows.push(current.data); } } // 4. 一次性写入清理后的数据到Master ssMaster.clear(); ssMaster.getRange(1, 1, cleanedRows.length, cleanedRows[0].length).setValues(cleanedRows); // 设置行高:先统一设置默认行高,再单独设置高行 ssMaster.setRowHeightsForced(2, cleanedRows.length - 1, 26); tallRowIndices.forEach(rowNum => { if (rowNum <= cleanedRows.length) { ssMaster.setRowHeightsForced(rowNum, 1, 136); } }); // 5. 查找并复制DELIVERY及之后的行 let deliveryRowIndex = -1; // 从第4行开始查找(数组索引3) for (let i = 3; i < allData.length; i++) { if (allData[i][0] === "DELIVERY") { deliveryRowIndex = i; break; } } if (deliveryRowIndex !== -1) { const deliveryData = allData.slice(deliveryRowIndex); const startRow = cleanedRows.length + 1; ssMaster.getRange(startRow, 1, deliveryData.length, deliveryData[0].length).setValues(deliveryData); } // 可选:恢复注释里的求和公式 // const finalRow = ssMaster.getLastRow(); // ssMaster.getRange(finalRow, 10).setFormula(`=sum(J2:J${finalRow - 1})`); // ssMaster.getRange(finalRow, 11).setFormula(`=sum(K2:K${finalRow - 1})`); // ssMaster.getRange(finalRow, 13).setFormula(`=sum(M2:M${finalRow - 1})`); // ssMaster.getRange(finalRow, 15).setFormula(`=M${finalRow} - K${finalRow}`); }
优化效果说明
- 原代码循环中每次
getRange()都会触发一次服务器请求,重构后只需要几次批量读写,速度能提升5-10倍 - 内存中过滤行数据,避免了反复删除、插入行的低效操作(这类操作每次都会重新渲染工作表,非常耗时)
- 用Map映射表替代公式匹配,省去了临时列P的写入、读取、清空步骤
- 统一设置行高后再单独调整高行,减少行高设置的调用次数
内容的提问来源于stack exchange,提问作者Chantie1126
相关产品推荐
相关产品推荐

