Порядок выполнения файлов GS в проекте

Где я могу прочитать документацию, касающуюся правил порядка выполнения для файлов GS?

Чтобы измерить проблему, я создал два тривиальных объекта, каждый в своем собственном файле.

1_File.gs

var ObjB = new Object();
ObjB.sayName = "[" + ObjA.sayName + "]";

0_File.gs

var ObjA = new Object();
ObjA.sayName = " I'm A ";

Вызов, такой как...

Logger.log(ObjA.sayName + " : " + ObjB.sayName);

... получает ошибку...

TypeError: Cannot read property "sayName" from undefined.

Если я переведу код из 1_File.gs в 0_File.gs, и наоборот, тогда нет ошибки, и журнал показывает правильно...

Я - A: [Я - A]

Переименование 0_File.gs на 2_File.gs также не влияет на порядок выполнения, поэтому я предполагаю, что порядок зависит от того, какой файл создается первым.

Разве нет понятия "включить" или "импорт", что позволило бы мне сделать порядок выполнения явным?

Ответ 1

Где я могу прочитать документацию, касающуюся правил порядка выполнения для файлов GS?

Нет такой документации, и я думаю, что не будет опубликовано какое-либо время. Аналогичным образом, порядок инициализации статических переменных в C++ также не определен и зависит от компилятора/компоновщика.

Разве нет понятия "включить" или "импорт", что позволило бы мне сделать порядок выполнения явным?

Да, нет "включений", "импорта" и даже "модулей", но есть библиотеки.

Также есть временное решение, используя закрытие. Ниже приведен пример кода. Выполняя тестовую функцию, журнал содержит cd. Идея состоит в том, чтобы во всех gs файлах была запущена функция init. В этих функциях отображаются все глобальные переменные. Анонимное закрытие выполняется во время Code.gs файла Code.gs и вызывает все "init" функции всех gs файлов.

Code.gs

var c;

function callAllInits_() {
  var keys = Object.keys(this);
  for (var i = 0; i < keys.length; i++) {
    var funcName = keys[i];
    if (funcName.indexOf("init") == 0) {
      this[funcName].call(this);
    }
  }
}

(function() {
  callAllInits_();
  c = { value : 'c.' + d.value };
})();

function test() {
  Logger.log(c.value);
}

d.gs

var d;

function initD() {
  d = { value : 'd' };
};

Ответ 2

Если у вас более одного уровня наследования, вам нужно предоставить имена функций инициализации, такие как init000Foo, init010Bar и init020Baz, а затем отсортировать функции init по имени перед выполнением. Это гарантирует, что init000Foo сначала оценивается, затем Bar, а затем Baz.

function callAllInits() {
  var keys = Object.keys(this);
  var inits = new Array();
  for (var i = 0; i < keys.length; i += 1) {
    var funcName = keys[i];
    if (funcName.indexOf("init") == 0) {
      inits.push(funcName);
    }
  }

  inits.sort();
  for (var i = 0; i < inits.length; i += 1) {
    // To see init order:
    // Logger.log("Initializing " + inits[i]);
    this[inits[i]].call(this);
  }
}

Ответ 3

В Google Apps Script такого порядка нет. Это зависит исключительно от того, где вы объявили эти объекты и как вызывается ваша функция. Можете ли вы немного рассказать о том, как и когда вызывается код Logger.log(). Кроме того, когда вы объявляете свои объекты objA и objB? Это поможет нам обеспечить лучший ответ

Ответ 4

Я решил эту проблему, создав класс в каждом файле и убедившись, что каждый класс Code.gs в исходном Code.gs (который я переименовал в _init.gs). Инициирование каждого класса действует как форма include и гарантирует, что все будет на месте перед выполнением чего-либо.

_init.gs:

// These instances can now be referred to in all other files
var Abc  = new _Abc();
var Menu = new _Menu();
var Xyz  = new _Xyz();
var Etc  = new _Etc();

// We need the global context (this) in order to dynamically add functions to it
Menu.createGlobalFunctions(this);

function onInstall(e) {
  onOpen(e);
}

function onOpen(e) {
  Menu.build();
}

И классы обычно выглядят так:

menu.gs:

function _Menu() {
  this.build = function() {
    ...
  }

  ...
}

Ответ 5

вот как я это сделаю...

главный

function include(filename) {
  return ContentService.createTextOutput(filename);
}

function main() {
  include('Obj A');
  include('Obj B');
  Logger.log(ObjA.sayName + " : " + ObjB.sayName);
}

Obj A

var ObjA = new Object();
ObjA.sayName = " I'm A ";

Obj B

var ObjB = new Object();
ObjB.sayName = "[" + ObjA.sayName + "]";

Ответ 6

Другие ответы (т.е. Не пишут код верхнего уровня, который ссылается на объекты в других файлах) описывают идеальный способ избежать этой проблемы. Однако, если вы уже написали много кода и переписываете, это невозможно, есть временное решение:

Сценарий Google App Script загружает файлы кода в том порядке, в котором они были созданы. Самый старый файл сначала, затем следующий и последний созданный файл. Это порядок, отображаемый в редакторе, когда флажок "Сортировка файлов по алфавиту" не установлен.

Таким образом, если у вас есть файлы в этом порядке:

  • Code.gs
  • 1_File.gs (зависит от 0_File.gs)
  • 0_File.gs

Легкое исправление заключается в том, чтобы сделать копию 1_File.gs, а затем удалить оригинал, эффективно перемещая его в конец списка.

  1. Нажмите треугольник рядом с 1_File.gs и выберите "Сделать копию",
    • Code.gs
    • 1_File.gs
    • 0_File.gs
    • 1_File copy.gs
  2. Щелкните треугольник рядом с 1_File.gs и выберите "Удалить".
    • Code.gs
    • 0_File.gs
    • 1_File copy.gs
  3. Нажмите треугольник рядом с 1_File copy.gs и выберите "Переименовать", а затем удалите "копию" с конца.
    • Code.gs
    • 0_File.gs
    • 1_File.gs

Теперь 0_File.gs загружается до 1_File.gs.