Сумин Андрей, 22 августа 2007.
Используя динамическую загрузку, я могу легко загружать нужные контенту страницы js файлы, а с помощью алиасов делать ссылки не на файлы, а на нужный функционал.
Алиасы позволяют разбивать js файлы на группы. Удобно отделить файлы ядра от файлов конкретного проекта, но если проект достаточно большой или много функционала, требующегося на нескольких проектах, то разбиение становится достаточно сложным. И я (на другом уровне) столкнулся с проблемой, с которой начинал: файлы каких алиасов могут понадобится на странице (напомню, что для подключения алиаса надо загрузить описывающий его файл)?
Расположение js фалов, как правило, зависит от js программиста, поэтому я решил перенести указание пути из HTML в js (не нарушая прежний алгоритм работы). Создаю объект для управления алиасами:
var expectedAliases = [];
var Locator = new function(){
this.aliases = [];
// устанавливает алиас
this.set = function(name, alias){
this.aliases[name] = alias;
// если этот алиас уже ожидается,
// то выполняю загрузку алиаса
if(expectedAliases[name]){
this.load(name);
}
};
// возвращает алиас, если таковой уже установлен
this.get = function(alias){
return this.aliases[alias] || null;
};
// загружает алиас, если он еще не загружен и не
// грузится в данный момент
this.load = function(alias){
if (!this.get(alias) || this.get(alias).called){
return;
}
this.get(alias).called = true;
createScript(this.get(alias).src, this.get(alias).charset);
};
};
Установка алиаса (set) - установление ссылки на объект, в котором содержится ссылка на файл. В файле находится описание алиаса. Если алиас требуется - загружает алиас.
Получение алиаса (get) - возвращает алиас.
Загрузка алиаса (load) - генерирует тег <script>, который загружает файл с описанием алиаса.
Если пока не рассматривать алгоритм установки алиасов, то в функции
require
, встретив неизвестный алиас, нужно записать в массив expectedAliases["неизвестный алиас"] функцию, которую надо выполнить при загрузке алиаса, и вызвать его загрузку Locator.load("неизвестный алиас"). Если такой алиас уже установлен, то начнется его загрузка. Если не установлен, то во время установки наличие непустого expectedAliases["неизвестный алиас"] послужит сигналом к его загрузке.
В связи с тем, что алиас может быть нужен раньше, чем он будет загружен, его установку нужно делать сложнее, чем описано в предыдущей статье.
var aliases = {};
function setAlias(name, value){
aliases[name] = value;
if (!expectedAliases[name]){
return;
}
// если кто-то уже ждет этот алиас
var listener;
while ((listener = expectedAliases[name].shift())){
listener();
}
};
Теперь осталось только установить значения ссылок на файлы описания алиасов.
Locator.set('alias1', {src: 'pathToAlias1', charset: 'utf-8', called: false});
Locator.set('alias2', {src: 'pathToAlias2', charset: 'utf-8', called: false});
Эти описания могут храниться в разных фалах и подключаться на странице в любой момент времени. У меня по одному файлу на проект.
В результате, если нужно загрузить файл, а описания его алиаса еще нет, то я запоминаю функцию загрузки файла в массив expectedAliases["неизвестный алиас"] и пытаюсь загрузить алиас Locator.load("неизвестный алиас"). Если путь к файлу описания известен, то этот файл грузится, если нет - при установке алиаса Locator.set("неизвестный алиас") я проверяю, не ждет ли его какой-либо файл (если ждет, то тоже начинаю загрузку описания алиаса). Когда описание алиаса загрузилось и устанавливается алиас теперь уже в ядре, я еще раз проверяю на ожидание этого алиаса файлами (при наличии таковых начинаю их загружать).
В результате, на всех страницах у меня подключается 2 файла.
<script src="path/jsx.js" type="text/javascript"></script>
<script src="path/locator.js" type="text/javascript"></script>
Первый - файл ядра, который обеспечивает динамическую загрузку и работу с алиасами, а во втором файле описаны пути ко все алиасам, которые могут понадобиться на проекте. И если где-то на проекте вдруг нужен новый алиас, то я просто дописываю путь к нему в locator.js.
Пример.