Модули Appcelerator и CommonJS (кэширование и циклические ссылки)

Вот в чем дело:

Я использую способ CommonJS для создания модульного мобильного приложения (iPhone/Android). Ничего удивительного. Но есть одна вещь, которую я никак не могу уложить в голове.

CommonJS позволяет мне создавать СТАТИЧЕСКИЕ закрытые переменные, что позволяет мне легко создавать синглтоны. По крайней мере, я думаю, это связано с тем, что содержимое файла, который получает 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)

person pancake    schedule 02.06.2012    source источник


Ответы (1)


Я тоже использую модули CommonJS в Appcelerator Titanium для создания мобильного приложения. Что я сделал, чтобы решить проблему циклической зависимости, так это: если A и B являются двумя циклически зависимыми модулями, require(A) в B и наоборот непосредственно перед тем, как вам действительно нужно его использовать . В моем случае мне нужно было A внутри B только тогда, когда была нажата определенная кнопка, поэтому я поместил require(A) в B внутри прослушивателя событий нажатия кнопки. Надеюсь, это поможет.

person Vicky Chijwani    schedule 24.06.2012
comment
Большое спасибо, это сэкономило много времени. - person nadeem gc; 13.08.2014