如何确保脚本块在下一个块之前首先运行?
How to make sure a block of Script runs first, before the next block?
抱歉,如果这是一个基本问题,但我就是无法按照我需要的方式工作。
我有一个基本上由 3 个部分组成的脚本:
1).移除 sheet
中的所有保护
2).执行一些复制功能(因为范围受到保护,我需要先取消保护#1)
3).在#2 完成后将保护设置备份。
这是我的代码:
首先清除保护
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
第二次清除单元格中的数据
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
Third sets protection
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
var costReportPurchaseEnding = ss.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
为了便于调试,我已经删减了一些脚本,但基本上我需要脚本按此顺序执行并完成,一个接一个。如果你只是按原样尝试 运行ning 脚本,保护不会被删除,我会收到错误 "trying to edit protected range...."
如果我 运行 每个块本身就可以完美运行,但是它包含 3 个不同的脚本,用户必须 运行 而我需要将它们合而为一。
提前致谢!
肖恩。
是这样的吗?
function removeProtection() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
};
function clearRangeData() {
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
};
function weeklyFileRangeProtection() {
//COST REPORT
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
};
我相信你有点误诊了这个问题。代码已经 运行 以正确的顺序排列,但由于 Google 的底层架构的性质,在执行写入调用之前,保护根本没有被删除。
引导您走向异步行为的评论在这种情况下没有帮助,从 Javascript 的角度来看它们确实有意义,但不是这里的问题,这是一个 Apps 脚本/Google 表格问题,none 您调用的函数是异步的。
我有两个建议,一个是在取消保护后尝试调用SpreadsheetApp.flush()
。另一种是在执行 remove() 调用后使用 Utilities.sleep()
人为地暂停脚本一段时间。
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush()
https://developers.google.com/apps-script/reference/utilities/utilities#sleep(Integer)
您遇到问题是因为您正在为每个函数调用 SpreadsheetApp.getActiveSpreadsheet
。每次进行此调用时,您都会创建一个虚拟的 "copy" 电子表格,并且您对此副本所做的更改只会在整个脚本完成后传递到 Google 服务器中的版本。因此,如果您手动 运行 工作流程的 3 个函数中的每一个:
运行 函数 1 -> 脚本完成 -> 更新服务器中的电子表格 -> 运行 函数 2(现在获取更新后的电子表格) -> 脚本完成 -> 更新电子表格在服务器中 -> 运行 函数 3(现在获取重新更新的电子表格) -> 脚本完成 -> 在服务器中更新电子表格
现在,如果你 运行 这三个函数,这里的脚本是这样的:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
这会创建一个电子表格的虚拟副本 -> 您的代码会移除此副本的保护并且不会修改服务器电子表格 -> 您再次调用 var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
创建一个新副本服务器电子表格的保护尚未移除 -> 您的代码试图清除此副本上的数据,这会触发错误。
正如@Cameron Roberts 在他的回答中所建议的那样 Spreadsheet.flush()
调用之间将解决问题,因为如果强制将更改同步到服务器中的电子表格。但是你会有另外一个"problem",就是你调用的副本量,这个.getActiveSpreadsheet()
非常耗时!最好只进行一次调用,将其存储在一个变量中(您已经这样做了,它是您的变量 ss
)并对其进行所有编辑。
您的代码最终将如下所示:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var costReport = ss.getSheetByName('COST REPORT');
//First clear protection
var protections = costReport.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
};
};
//Second clears data in cells
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
//Third sets protection
var costReportCOGS = costReport.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
var costReportPurchaseEnding = costReport.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
此方法也适用于 Google Docs,它没有类似的 .flush()
更新服务器版本的方法。
抱歉,如果这是一个基本问题,但我就是无法按照我需要的方式工作。
我有一个基本上由 3 个部分组成的脚本:
1).移除 sheet
中的所有保护2).执行一些复制功能(因为范围受到保护,我需要先取消保护#1)
3).在#2 完成后将保护设置备份。
这是我的代码:
首先清除保护
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
第二次清除单元格中的数据
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
Third sets protection
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
var costReportPurchaseEnding = ss.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
为了便于调试,我已经删减了一些脚本,但基本上我需要脚本按此顺序执行并完成,一个接一个。如果你只是按原样尝试 运行ning 脚本,保护不会被删除,我会收到错误 "trying to edit protected range...."
如果我 运行 每个块本身就可以完美运行,但是它包含 3 个不同的脚本,用户必须 运行 而我需要将它们合而为一。
提前致谢!
肖恩。
是这样的吗?
function removeProtection() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
};
function clearRangeData() {
var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(
'COST REPORT');
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
};
function weeklyFileRangeProtection() {
//COST REPORT
var ss = SpreadsheetApp.getActive().getSheetByName('COST REPORT');
var costReportCOGS = ss.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
};
我相信你有点误诊了这个问题。代码已经 运行 以正确的顺序排列,但由于 Google 的底层架构的性质,在执行写入调用之前,保护根本没有被删除。
引导您走向异步行为的评论在这种情况下没有帮助,从 Javascript 的角度来看它们确实有意义,但不是这里的问题,这是一个 Apps 脚本/Google 表格问题,none 您调用的函数是异步的。
我有两个建议,一个是在取消保护后尝试调用SpreadsheetApp.flush()
。另一种是在执行 remove() 调用后使用 Utilities.sleep()
人为地暂停脚本一段时间。
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#flush()
https://developers.google.com/apps-script/reference/utilities/utilities#sleep(Integer)
您遇到问题是因为您正在为每个函数调用 SpreadsheetApp.getActiveSpreadsheet
。每次进行此调用时,您都会创建一个虚拟的 "copy" 电子表格,并且您对此副本所做的更改只会在整个脚本完成后传递到 Google 服务器中的版本。因此,如果您手动 运行 工作流程的 3 个函数中的每一个:
运行 函数 1 -> 脚本完成 -> 更新服务器中的电子表格 -> 运行 函数 2(现在获取更新后的电子表格) -> 脚本完成 -> 更新电子表格在服务器中 -> 运行 函数 3(现在获取重新更新的电子表格) -> 脚本完成 -> 在服务器中更新电子表格
现在,如果你 运行 这三个函数,这里的脚本是这样的:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
这会创建一个电子表格的虚拟副本 -> 您的代码会移除此副本的保护并且不会修改服务器电子表格 -> 您再次调用 var costReport = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('COST REPORT');
创建一个新副本服务器电子表格的保护尚未移除 -> 您的代码试图清除此副本上的数据,这会触发错误。
正如@Cameron Roberts 在他的回答中所建议的那样 Spreadsheet.flush()
调用之间将解决问题,因为如果强制将更改同步到服务器中的电子表格。但是你会有另外一个"problem",就是你调用的副本量,这个.getActiveSpreadsheet()
非常耗时!最好只进行一次调用,将其存储在一个变量中(您已经这样做了,它是您的变量 ss
)并对其进行所有编辑。
您的代码最终将如下所示:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var costReport = ss.getSheetByName('COST REPORT');
//First clear protection
var protections = costReport.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
};
};
//Second clears data in cells
costReport.getRange('F12:F16').clearContent(); //Theoreticals
costReport.getRange('D20:D20').clearContent(); //Week Ending Date
//Third sets protection
var costReportCOGS = costReport.getRange('G11:G16');
var protection = costReportCOGS.protect().setDescription('costReportCOGS');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
var costReportPurchaseEnding = costReport.getRange('D11:E16');
var protection = costReportPurchaseEnding.protect().setDescription(
'costReportPurchaseEnding');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
};
此方法也适用于 Google Docs,它没有类似的 .flush()
更新服务器版本的方法。