Порядок выполнения файлов 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_File.gs и выберите "Сделать копию",
- Code.gs
- 1_File.gs
- 0_File.gs
- 1_File copy.gs
- Щелкните треугольник рядом с 1_File.gs и выберите "Удалить".
- Code.gs
- 0_File.gs
- 1_File copy.gs
- Нажмите треугольник рядом с 1_File copy.gs и выберите "Переименовать", а затем удалите "копию" с конца.
- Code.gs
- 0_File.gs
- 1_File.gs
Теперь 0_File.gs загружается до 1_File.gs.