0

I am trying to work with closures to speed up my script code in Google Scripts. The concept is new to me but I am wondering if the closure is applied correctly in the code below. (the code works)

Background: the code is to calculate how much a month has progressed in percentages.

I don't want the now and month variables to update every time the function is called but only once if the document is opened. What I essentially want is that all variables are set only once and that the function will deliver an answer if it's called multiple times.

Is this a good reason to use a closure and am I using it correctly?

Thanks for your advice and patience.

// calculate progress with second precision
var progressCalc = (function() { 

  const stMonth = SpreadsheetApp.getActive()
    .getRangeByName("pStartdate")
    .getValue();

  const eoMonth = SpreadsheetApp.getActive()
    .getRangeByName("pEndOfMonthDate")
    .getValue();

  const now = new Date();

  var unixProgressEoMonth = unixTime(eoMonth)-unixTime(stMonth)
  var unixProgressNow = unixTime(now)-unixTime(stMonth)

  return function () { return unixProgressNow/unixProgressEoMonth;};

})();

function progress() {
  Logger.log(progressCalc());
  return progressCalc();
}
Christoph
  • 1,347
  • 2
  • 19
  • 36
  • "*I am trying to work with closures to speed up my script code*" - Huh? Notice that your returned function (the closure) will always return the same value, so there's no point in executing it multiple times or repeating the division. You could as well just store the result value itself in a global `progressVal` variable, there's no need for `progressCalc`. – Bergi Jul 10 '17 at 14:08
  • I am not sure I understand what you mean. Could you perhaps make a quick example so I can look at it? – Christoph Jul 10 '17 at 14:44
  • We could make better answers if you could tell/show us where (how often) `progress` or `progressCalc` are called, and how your original code without closures looked like so that we might judge the speedup and whether you applied a pattern correctly. – Bergi Jul 10 '17 at 14:49
  • I use progress as a function within spreadsheet cells. I like to use it that way since it's easier to work with than having to define the range every time before I write the values. – Christoph Jul 10 '17 at 16:03
  • Come to think of it I could write it once and refer to that within my spreadsheet. That will solve the speed problem. – Christoph Jul 10 '17 at 16:12

1 Answers1

1

I am trying to work with closures to speed up my script code in Google Scripts.

Then you should not evaluate the calculation every time progressCalc is called.

Is this a good reason to use a closure?

No. In fact, your calculation has a constant result, so there's no point in putting it in a function and executing it multiple times at all. Instead of storing a function, just store the result value right away:

var progressValue = (function() { 

  const stMonth = SpreadsheetApp.getActive()
    .getRangeByName("pStartdate")
    .getValue();

  const eoMonth = SpreadsheetApp.getActive()
    .getRangeByName("pEndOfMonthDate")
    .getValue();

  const now = new Date();

  var unixProgressEoMonth = unixTime(eoMonth)-unixTime(stMonth)
  var unixProgressNow = unixTime(now)-unixTime(stMonth)

  return unixProgressNow/unixProgressEoMonth;
})();

function progress() {
  Logger.log(progressValue);
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Okay one last question: if I understand correctly the () will execute the function. So create the variable progressValue. Insert the nameless(?) function, execute it within the variable by putting () behind it. Next I can use progressValue everywhere without evaluating it if I do not put () behind it. – Christoph Jul 10 '17 at 16:07
  • @Christoph [This pattern](https://stackoverflow.com/questions/26092101/what-is-this-javascript-pattern-called-and-why-is-it-used) is called IIFE. No, the nameless function is not "inserted" anywhere, it's just created, executed, and forgotten. It does not know even about the variable. What gets assigned to the variable is the *return value* of the call - a number in our case - which is why we don't put () behind it when using it. – Bergi Jul 10 '17 at 19:16
  • Thanks for your help! This clarifies a lot. – Christoph Jul 10 '17 at 20:29