Google Sheets 脚本,自定义函数 运行 时间错误(30 秒)。如何使函数 运行 更快?
Google Sheets Script, Custom function runtime error (30seconds). How to make function run faster?
我正在尝试创建一个循环遍历“M”列并将每个单元格乘以一个常数(例如,10.5)的函数。我终于设法创建了一个执行此操作的函数,但它需要时间来执行并在完成之前遇到运行时错误,因为它需要超过 30 秒才能完全执行。你们认为有可能以某种方式加速我的代码吗?如果有人能指出我正确的方向,我将不胜感激。下面是我的代码。
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getRow() == 1 && cell.getColumn() == 13 && e.value != null){
if (cell.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (cell.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
var range = ss.getRange("M:M");
var count = range.getDisplayValues();
for(var i=2;i<count.length;i++){
ss.getRange("M"+ i).setValue(Number(ss.getRange("M"+ i).getDisplayValue())*valuta);
}
}
}
我认为问题在于您过多地使用了电子表格函数 - 您基本上是在 for 循环的每次迭代中与电子表格进行交互。这有很大的开销。
我提出两个想法:
1.代码修复: 我建议尽可能少地使用电子表格功能。它们非常昂贵。这意味着只检索一次范围,并且只更新一次范围。
这是我的建议:
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getRow() == 1 && cell.getColumn() == 13 && e.value != null){
if (cell.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (cell.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
// This is a reference to the range
var range = ss.getRange("M:M");
// This actually reads the values - do it only once
var count = range.getDisplayValues();
// This updates the count variable - does not interact with the spreadsheet yet
for(var i=2;i<count.length;i++){
count[i][0] *= valuta;
}
// This updates the range - done only once.
range.setValues(count);
}
}
代码尚未经过测试,如果有任何错误需要修复,请告诉我。
2。可选 :看看 - 特别是模式 #3。
如果在获取范围时忽略空白值,则可以使其更快。
function onEdit(e) {
const range = e.range;
if (range.getRow() === 1 && range.getColumn() === 13 && e.value) {
let valuta;
if (e.value === 'Currency EURO') { valuta = 10.5 }
if (e.value === 'Currency Pund') { valuta = 12.31 }
const sheet = e.source.getActiveSheet()
const values = sheet.getRange(`M2:M`)
.getDisplayValues()
.filter(String)
.map(i => [Number(i) * valuta])
sheet.getRange(2, 13, values.length, values[0].length).setValues(values)
}
}
这是您的函数的优化版本。
- 主要优化是所有数据更改都“一次性”处理
时间'.
- 二次优化是只有一次调用values
- 这也将处理任何空单元格,并避免第一行单元格。
这样试试:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == "Sheet Name" && e.range.rowStart == 1 && e.range.columnStart == 13 && e.value != null) {
if (e.range.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (e.range.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
let vs = sh.getRange("M2:M" + sh.getLastRow()).getDisplayValues().flat().map((e,i) => [e * valuta] )
sh.getRange("M2:M"+sh.getLastRow()).setValues(vs));
}
}
我正在尝试创建一个循环遍历“M”列并将每个单元格乘以一个常数(例如,10.5)的函数。我终于设法创建了一个执行此操作的函数,但它需要时间来执行并在完成之前遇到运行时错误,因为它需要超过 30 秒才能完全执行。你们认为有可能以某种方式加速我的代码吗?如果有人能指出我正确的方向,我将不胜感激。下面是我的代码。
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getRow() == 1 && cell.getColumn() == 13 && e.value != null){
if (cell.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (cell.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
var range = ss.getRange("M:M");
var count = range.getDisplayValues();
for(var i=2;i<count.length;i++){
ss.getRange("M"+ i).setValue(Number(ss.getRange("M"+ i).getDisplayValue())*valuta);
}
}
}
我认为问题在于您过多地使用了电子表格函数 - 您基本上是在 for 循环的每次迭代中与电子表格进行交互。这有很大的开销。
我提出两个想法:
1.代码修复: 我建议尽可能少地使用电子表格功能。它们非常昂贵。这意味着只检索一次范围,并且只更新一次范围。
这是我的建议:
function onEdit(e) {
var ss = e.source;
var cell = e.range;
if(cell.getRow() == 1 && cell.getColumn() == 13 && e.value != null){
if (cell.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (cell.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
// This is a reference to the range
var range = ss.getRange("M:M");
// This actually reads the values - do it only once
var count = range.getDisplayValues();
// This updates the count variable - does not interact with the spreadsheet yet
for(var i=2;i<count.length;i++){
count[i][0] *= valuta;
}
// This updates the range - done only once.
range.setValues(count);
}
}
代码尚未经过测试,如果有任何错误需要修复,请告诉我。
2。可选 :看看
function onEdit(e) {
const range = e.range;
if (range.getRow() === 1 && range.getColumn() === 13 && e.value) {
let valuta;
if (e.value === 'Currency EURO') { valuta = 10.5 }
if (e.value === 'Currency Pund') { valuta = 12.31 }
const sheet = e.source.getActiveSheet()
const values = sheet.getRange(`M2:M`)
.getDisplayValues()
.filter(String)
.map(i => [Number(i) * valuta])
sheet.getRange(2, 13, values.length, values[0].length).setValues(values)
}
}
这是您的函数的优化版本。
- 主要优化是所有数据更改都“一次性”处理 时间'.
- 二次优化是只有一次调用values
- 这也将处理任何空单元格,并避免第一行单元格。
这样试试:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == "Sheet Name" && e.range.rowStart == 1 && e.range.columnStart == 13 && e.value != null) {
if (e.range.getDisplayValue() == 'Currency EURO') {
var valuta = 10.5;
}
if (e.range.getDisplayValue() == 'Currency Pund') {
var valuta = 12.31;
}
let vs = sh.getRange("M2:M" + sh.getLastRow()).getDisplayValues().flat().map((e,i) => [e * valuta] )
sh.getRange("M2:M"+sh.getLastRow()).setValues(vs));
}
}