Very slow execution of for…in loop

断了今生、忘了曾经 提交于 2020-01-04 05:33:49

问题


I am populating a spreadhsheet from data I am getting from an external endpoint. Everything is working, but the execution of the for...in loop is incredibly slow.

The object that I am getting back from UrlFetchApp is quite large; Object.keys().length > 1500, so perhaps it could just be the size of the object.

I am curious if there is a way to optimize my function.

Code:

    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
        }
      }
    }

回答1:


I was not sure about //do something after complete. So how about these 2 patterns. Please think of this answer as one of several answers.

I modified your script to replace setValue() to setValues(). By this, the process speed will be fast.

Pattern 1 :

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);
}

Pattern 2 :

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
}

Note :

  • If this didn't work, can you provide a sample data from var response = UrlFetchApp.fetch(endpoint);? Of course, please remove the private information from it.

Refecences :

  • setValue(value)
  • setValues(values)
  • Best Practices

If I misunderstand your question, I'm sorry.




回答2:


The problem is not with the size of your object. You are repeatedly calling sheet.getRange() to get every individual cell in the target range which is redundant. Keep read/process/write operations completely separate from each other to optimize performance. 1) Retrieve values 2) Process them, and 3) Call 'setValues()' on the target range. This took less than 0.2 seconds to finish:

 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);


来源:https://stackoverflow.com/questions/48938168/very-slow-execution-of-for-in-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!