Zmienne globalne w skrypcie Google (arkusz kalkulacyjny)

Próbowałem uzyskać kilka funkcji w skrypcie Google apps (wewnątrz arkusza kalkulacyjnego), aby zmodyfikować zmienną globalną, ale nie mogę tego rozgryźć.

Zasadniczo chcę zadeklarować zmienną (w tym przypadku "globalTestVar"), i za każdym razem, gdy jedna z dwóch funkcji (globalVarTestFunctionOne i two) uruchomi tę zmienną powinna zostać zwiększona o jedną.

Problem polega na tym, że zmienna jest deklarowana ponownie za każdym razem, gdy naciśnięty jest przycisk, mimo że if(typeof(globalTestVar) == 'undefined')-polecenie powinno się tym zająć.

Jestem przyzwyczajony do Objective C i Java, gdzie mogę zadeklarować moje zmienne na początku i modyfikować te zmienne w dowolnym miejscu w kodzie.

Przepraszam, jeśli to jest podstawowe pytanie, ale googluję od kilku godzin i po prostu nie mogę go uruchomić.

Oto kod:

logstuff("outside");


function logstuff(logInput){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var lastRow = sheet.getLastRow() + 1;
sheet.getRange("A"+lastRow).setValue(logInput);
return;
}


if (typeof(globalTestVar) == 'undefined') {
logstuff('declaring global variable');
globalTestVar = 0;

} else {
logstuff('global variable has been declared'); 
}



function globalVarTestUIFunction() {
var app = UiApp.createApplication().setTitle('Test UI');
var doc = SpreadsheetApp.getActive();
var formPanel = app.createVerticalPanel();


var buttonF1 = app.createButton('F1');
var buttonbuttonF1ClickHandler = app.createServerClickHandler("globalVarTestFunctionOne");
buttonF1.addClickHandler(buttonbuttonF1ClickHandler);
buttonbuttonF1ClickHandler.addCallbackElement(formPanel);

var buttonF2 = app.createButton('F2');
var buttonbuttonF2ClickHandler = app.createServerClickHandler("globalVarTestFunctionTwo");
buttonF2.addClickHandler(buttonbuttonF2ClickHandler);
buttonbuttonF2ClickHandler.addCallbackElement(formPanel);


app.add(formPanel);

formPanel.add(buttonF1);
formPanel.add(buttonF2);


doc.show(app);

return app;
}



function globalVarTestFunctionOne() {
logstuff('globalVarTestFunctionOne');
globalTestVar++;
logstuff('Value of globalTestVar: ' + globalTestVar);
}

function globalVarTestFunctionTwo() {
logstuff('globalVarTestFunctionTwo');
globalTestVar++;
logstuff('Value of globalTestVar: ' + globalTestVar);
}

Wyjście:

  • outside3
  • deklarowanie globalnego zmienna
  • outside3
  • deklarowanie zmiennej globalnej
  • globalVarTestFunctionOne
  • wartość globalTestVar: 1
  • outside3
  • deklarowanie zmiennej globalnej
  • globalVarTestFunctionTwo
  • wartość globalTestVar: 1

Napisałem własną funkcję "logstuff" do drukowania wiadomości, ponieważ nie podoba mi się Wbudowany Logger.funkcja logowania.

Dziękuję!
Author: Mogsdad, 2013-06-29

3 answers

Nie spodoba ci się to: zmienne globalne w gazie są statyczne - nie możesz ich aktualizować i oczekiwać, że zachowają swoje wartości. Też to wygooglowałem godzinami.

Możesz użyć CacheService LUB ScriptDB jako możliwego magazynu dla tego rodzaju problemów. CacheService jest szybki i łatwy w użyciu, ale ograniczony, ponieważ pamięć podręczna wygaśnie w końcu. Nie próbowałem ScriptDB

 16
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-29 00:25:45

PropertiesService - > Properties

Obecnie (2015), myślę, że sposobem na przejście jest użycie właściwości klasyPropertiesService i właściwości typu return .

O zasięgu globalnym

Jak rozumiem, każde nowe wywołanie funkcji skryptu (wyzwalacze czasowe, kliknięcie przez użytkownika elementu menu, naciśnięcie przycisku, itp.), prowadzi do nowego pełnego parsowania skryptu bez pamięci wcześniejszych egzekucji, chyba że zostały jakoś utrzymane (w arkuszu kalkulacyjnym lub w arkuszu kalkulacyjnym). używając na przykład Properties).

 13
Author: consideRatio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-12 10:50:05

Pomimo CacheService będzie działać, ma maksymalny czas życia 6 godzin. Można to rozwiązać za pomocą PropertiesService, jak wspomniano @consideRatio.

Przykładowy wrapper może być (wstrzykuje zmienne do globalnego kontekstu)

/* Wrap variable inside global context */
const Globals = {
  global:this,
  items:{},
  /* Can be 'User', 'Script', or 'Document'
  ** Script - same values for all executions of this script
  ** User - same values for all executions by same user
  ** Document - same values for any user for same document
  ** Check reference for details.
  ** https://developers.google.com/apps-script/guides/properties
  **
  */
  context:'Script', 
  /* Get property service based on requested context */
  get service() {
    return PropertiesService['get' + this.context + 'Properties']()
  },
  /* Assign implementation */
  set(name, value = null) {
    this.service.setProperty(name, JSON.stringify(value));
    return value;
  },
  /* Read implementation */
  get(name) {
    var value = this.service.getProperty(name);
    return value !== null? JSON.parse(value) : null;
  },
  /* Shortcut for setter of complex objects */
  save(name) {
    this.set(name, this.items[name]);
  },
  /* Save all */
  flush(name) {
    Object.keys(this.items).map(name => this.save(name));
  },
  /* Delete implementation */
  reset(name) {
    this.service.deleteProperty(name);
    delete this.items[name];
  },
  /* Add to global scope */
  init(name, default_value = null) {
    if(! this.items.hasOwnProperty(name)) {
      if(this.service.getProperty(name) === null)
        this.set(name, default_value);
      this.items[name] = this.get(name);
      Object.defineProperty(this.global, name, {
        get: () => {return this.items[name]},
        set: (value) => {return this.items[name] = this.set(name, value)},
      })
    }
    return this.items[name];
  }
}
Po zarejestrowaniu się w Globals.INIT, zmienne mogą być używane tak jak zwykłe zmienne. Działa to jednak z prymitywami, ponieważ obserwatory nie są obsługiwane dla złożonych obiektów, muszą być spłukane na końcu skryptu lub jawnie.
/* In case you need to start over */
function restart_simulations() {
  Globals.reset('counter');
  Globals.reset('state');
  
  test_run();
}

function test_run() {
  /* After running init once, you can use global var as simple variable */
  Globals.init('counter', 1); // Required to use "counter" var directly, as simple variable
  
  /* Complex objects are also accepted */
  Globals.init('state', { logined: false, items: [] }); 
  
  /* Using primitives is simple */
  Logger.log('Counter was ' + counter);
  counter = counter + 1;
  Logger.log('Counter is now ' + counter);

  /* Let's modify complex object */
  Logger.log('State was ' + JSON.stringify(state));
  
  state.items.push(state.logined ? 'foo' : 'bar');
  state.logined = ! state.logined;
  
  Logger.log('State is now ' + JSON.stringify(state));
  
  /* Unfortunately, watchers aren't supported. Non-primitives have to be flushed */
  /* Either explicitly */
  //Globals.save('state');  
  
  /* Or all-at-once, e.g. on script end */
  Globals.flush();  
}

Oto co jest zachowane wśród różnych 3 biegów

First run:

[20-10-29 06:13:17:463 EET] Counter was 1
[20-10-29 06:13:17:518 EET] Counter is now 2
[20-10-29 06:13:17:520 EET] State was {"logined":false,"items":[]}
[20-10-29 06:13:17:523 EET] State is now {"logined":true,"items":["bar"]}

Second run:

[20-10-29 06:13:43:162 EET] Counter was 2
[20-10-29 06:13:43:215 EET] Counter is now 3
[20-10-29 06:13:43:217 EET] State was {"logined":true,"items":["bar"]}
[20-10-29 06:13:43:218 EET] State is now {"logined":false,"items":["bar","foo"]}

Third run:

[20-10-29 06:14:22:817 EET] Counter was 3
[20-10-29 06:14:22:951 EET] Counter is now 4
[20-10-29 06:14:22:953 EET] State was {"logined":false,"items":["bar","foo"]}
[20-10-29 06:14:22:956 EET] State is now {"logined":true,"items":["bar","foo","bar"]}

Możesz sprawdzić przykład pracy tutaj.

Skrypt Demo

 0
Author: roma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-29 04:29:43