Модули Appcelerator и CommonJS (кеширование и циклические ссылки)
Вот в чем дело:
Я использую способ CommonJS, чтобы сделать мое мобильное (iPhone/Android) приложение модульным. Там нет ничего удивительного. Но есть одна вещь, которую я просто не могу понять.
CommonJS позволяет мне создавать приватные переменные STATIC, что позволяет легко создавать синглтоны. Это, я думаю, по крайней мере, потому, что содержимое файла, который получает require()
d читается только один раз, а затем каждый раз возвращается объект экспорта (который инициализируется только один раз).
Но когда я создаю циклическую ссылку, как показано ниже, код внутри включенного модуля выполняется каждый раз.
Подожди... Забавно, когда я пишу этот вопрос, я вдруг понимаю, что ни один из звонков require()
закончите до начала следующего (следовательно, переполнение стека показано ниже).
Любые мысли о том, на ходу я или нет? Здесь уже 5 часов утра, так что все ставки сделаны, насколько я могу судить:D.
ПРИМЕРЫ:
Посмотрите этот кусок кода, он определяет синглтон:
/* Singleton.js */
exports.getSingleton = getSingleton;
function getSingleton(name) {
if (!instance) {
instance = new Thing(name);
}
return instance;
}
function Thing(name) {
this.name = name;
}
var instance;
я require()
этот файл как таковой:
var theFirstThing = require('Singleton').getSingleton('first');
Ti.API.info('first: ' + theFirstThing.name)
var possiblyAnotherOtherThing = require('Singleton').getSingleton('second');
Ti.API.info('second: ' + possiblyAnotherOtherThing.name);
Выход:
[DEBUG] loading: /path/to/sim/MyApp.app/app.js, resource: app_js
[DEBUG] loading: /path/to/sim/MyApp.app/Singleton.js, resource: Singleton_js
[INFO] first: first
[INFO] second: first
Почему циклические ссылки, подобные следующим, не работают? (Я, возможно, уже ответил на этот вопрос сам, прокомментируйте / ответьте на него, если хотите).
app.js
require('Banana');
Pinapple.js
require('Banana');
Banana.js
require('Pineapple');
Потому что вывод таков:
[DEBUG] loading: /path/to/simulator/MyApp.app/app.js, resource: app_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Banana.js, resource: Banana_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Pineapple.js, resource: Pineapple_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Banana.js, resource: Banana_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Pineapple.js, resource: Pineapple_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Banana.js, resource: Banana_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Pineapple.js, resource: Pineapple_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Banana.js, resource: Banana_js
/* etcetera (total of 15 times back and forth) */
[DEBUG] loading: /path/to/simulator/MyApp.app/Pineapple.js, resource: Pineapple_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Banana.js, resource: Banana_js
[DEBUG] loading: /path/to/simulator/MyApp.app/Pineapple.js, resource: Pineapple_js
[ERROR] Script Error = Maximum call stack size exceeded. (unknown file)
1 ответ
Я также использую модули CommonJS в Appcelerator Titanium для создания мобильного приложения. Что я сделал для решения проблемы циклических зависимостей, так это: если A и B являются 2 циклически зависимыми модулями, требуют (A) в B, и наоборот, непосредственно перед тем, как вам на самом деле нужно его использовать. В моем случае, я нуждался в A внутри B, только когда нажата определенная кнопка, поэтому я поместил require (A) в B внутри слушателя события нажатия кнопки. Надеюсь, это поможет.