【问题标题】:Very slow execution of for...in loopfor...in 循环的执行速度非常慢
【发布时间】:2023-11-10 14:04:01
【问题描述】:

我正在根据从外部端点获取的数据填充电子表格。一切正常,但 for...in 循环的执行速度非常慢。

我从UrlFetchApp 返回的对象非常大; Object.keys().length > 1500,所以可能只是对象的大小。

我很好奇是否有办法优化我的功能。

代码:

    var sh = SpreadsheetApp.getActiveSheet();
    function getData() {
      var response = UrlFetchApp.fetch(endpoint);
      var data = JSON.parse(response);
      var rates = data["quotes"];
      var max = Object.keys(rates).length;
      var row = 2;
      var i = 0;
      clear(); //clears the range A2:B
      for (var key in rates) {
        sh.getRange("A" + (i+row)).setValue(key.substring(3));
        sh.getRange("B" + (i+row)).setValue(rates[key]);
        i++
        if (i+1 === max) {
          //do something after complete
        }
      }
    }

【问题讨论】:

    标签: javascript performance optimization google-apps-script google-sheets


    【解决方案1】:

    我不确定//do something after complete。那么这两种模式怎么样。请将此答案视为多个答案之一。

    我修改了您的脚本以将 setValue() 替换为 setValues()。这样,处理速度会很快。

    模式一:

    function getData1() {
      var sh = SpreadsheetApp.getActiveSheet();
      var response = UrlFetchApp.fetch(endpoint);
      var data = JSON.parse(response);
      var rates = data["quotes"];
    
      var keys = Object.keys(rates);
      var dat = [];
      keys.forEach(function(key){
        if (key != keys[keys.length - 1]) {
          dat.push([key.substring(3), rates[key]]);
        } else {
          //do something after complete
        }
      });
      sh.getRange(2, 1, dat.length, dat[0].length).setValues(dat);
    }
    

    模式二:

    function getData2() {
      var sh = SpreadsheetApp.getActiveSheet();
      var response = UrlFetchApp.fetch(endpoint);
      var data = JSON.parse(response);
      var rates = data["quotes"];
    
      var dat = Object.keys(rates).map(function(key){return [key.substring(3), rates[key]]});
      sh.getRange(2, 1, dat.length, dat[0].length).setValues(dat);
    
      //do something after complete
    }
    

    注意:

    • 如果这不起作用,您能否提供来自var response = UrlFetchApp.fetch(endpoint); 的示例数据?当然,请删除其中的私人信息。

    参考:

    如果我误解了你的问题,我很抱歉。

    【讨论】:

    • 太棒了,这工作就像一个魅力。我猜我不需要clear() 函数,因为我们只是覆盖了现有数据?
    • @justinw 我认为如果要覆盖的数据与原始数据相同或大于原始数据,则可以删除clear()
    • @Tanaike 我没有记录执行时间,但它从 6 多分钟变为看似大约需要几秒钟 :)
    • @justinw 感谢您提供更多信息。我很高兴大大缩短了处理时间。
    【解决方案2】:

    问题不在于对象的大小。您反复调用 sheet.getRange() 以获取目标范围内的每个单独的单元格,这是多余的。保持读/处理/写操作彼此完全分开以优化性能。 1) 检索值 2) 处理它们,以及 3) 在目标范围上调用“setValues()”。完成时间不到 0.2 秒:

     var arr = [];
    
      for (var [prop, val] in hugeObject) {
    
        arr.push([prop, val]);  
    
      }
    
      var targetRange = SpreadsheetApp.getActive()
                                      .getSheets()[0]
                                      .getRange(2, 1, arr.length, arr[0].length)
                                      .setValues(arr);
    

    【讨论】:

      最近更新 更多