[recovery mode] Наш вариант подхода к написанию JS приложений. Загрузка скриптов и проксирование
Приветствую Всех! В прошлый раз, то ли по неопытности, то ли ещё по какой причине — выложив статью я не смог отстоять своё мнение по поводу «необходимости» написания своего «велосипеда» (как некоторые это назвали) для масштабируемых JS приложений. На это положило отпечаток то что проект находится в разработке, и некоторые скрипты выложить я ну никак не мог.Но сегодня я всё-же хочу постараться переубедить всех противников такого «велосипедостроения» в том что это действительно было необходимо, и покажу конкретные примеры, и с конкретными же исходниками.Вступление Начну пожалуй с того что статья позволила мне собраться и привести код в частичный порядок, за что большое спасибо всем критикам.Но от своих «велосипедов» мы не отказались, об этом ниже.Проект является достаточно большим, и конкретно до меня писался 3–4 программистами, и у каждого из них было своё видение по структуре и общим правилам кода.И именно кем-то из них была придумана такая структура какая она есть, но как мне кажется разделение проекта на составные части (директории и области видимости) является хорошей, и даже полезной практикой:
разделение директорий и файлов позволяет лучше вникать в ООП и разделять логику и интерфейс. разделение областей видимости для каждого из компонентов — даёт возможность избежать пересечения интересов. Исходя из этого, и того что проект достаточно специфичен у нас имеется 2 ключевых скрипта которые представляют из себя «ядро» сайта: boot.js — который занимается загрузкой скриптов (эдакий аналог RequireJS) и прочими функциями при загрузке (инициализация, создание классов, наследование и т.д.) processor.js — который занимается проксированием всех функций в наших областях видимости. boot.js Основная задача данного скрипта — это (под)загрузка модулей из 3х системных директорий: libraries modules addons Загрузка происходит путём обращения к файлу *.boot.js в одноимённой директории, а вызывается вот так: /* Библиотеки */ boot.libraries ([ 'area', 'window' ], function () { /* Модули */ boot.modules ([ 'account', 'settings' ], function () { /* Аддоны */ boot.addons ([ 'debugUtils', 'vFile', 'vAudio', 'vVideo' ], function () { // Проксируем области видимости core и interface processor.proxy (core, 'core'); processor.proxy (interface, 'interface'); }); }); }); Исходя из этого загрузка будет выглядеть так (пример на библиотеке «window»): скрипт загружает файл по адресу /libraries/window/window.boot.js в нём в свою очередь прописаны другие скрипты которые находятся в этой-же папке: // Загружаем файл window.style.css boot.css ({ file: 'window.style' }); // Загружаем файл windows.core.js и вызываем функцию core.windows.initialize boot.js ({ file: 'windows.core', initialize: [ 'core.windows' ] }); // Загружаем файл Window.interface.js, но перед этим производим загрузку библиотеки area если она ещё не загружена boot.js ({ file: 'Window.interface', require: [ 'area' ] }); загружаются файлы из *.boot.js исходя из прописанных параметров. boot.js и «классы» Кроме загрузки модулей, boot.js берёт на себя так же функции по созданию правильных (по нашему мнению) классов и их наследовании. var Area = boot.createClass (interface, 'Area', function () { /** Создаём класс Area в области видимости interface **/ });
Area.prototype.showOrHide = function (state) { /** Какой-то код **/
return this; }; var Window = boot.createClass (interface, 'Window', function () { /** Создаём класс Window в области видимости interface и наследуемся от interface.Area **/ }, interface.Area);
Window.prototype.showOrHide = function (state) { var newState = ! state; this.parentFunction ('showOrHide')(newState); // Вызываем функцию родителя
return this; }; var Area = new interface.Area (); var Window = new interface.Window (); processor.js Данный скрипт позволяет нам использовать событийную модель, и вмешиваться в работу другого модуля — так что-бы он о нас не знал.Данный функционал очень полезен, так как даёт возможность писать модули и аддоны которые в случае своего отключения — ничего не ломают.У процессора есть 5 функций которые очень схожи с аналогичными в JQuery:
proxy — проксирование заданного объекта (посмотреть можно в примере работы boot.js) signal — произвести сигнал на который можно прикрепить обработчик (некий аналог $.trigger ()) bind — прикрепить обработчик на вызов функции или сигнал unbind — открепить обработчик one — прикрепить обработчик который сработает только один раз Вот небольшой пример использование таких вот «обработчиков».Допустим мы вызываем функцию interface.Window.showOrHide (true);, из другого модуля мы можем перехватить её вот так: // Цепляемся на начало выполнения функции 'interface.Window.showOrHide' — из аддона. processor.bind ('interface.Window.showOrHide', function (sender, params) { console.log ('Значение в начале выполнения функции: ' + params[0]); params[0] = false; // Меняем входящее значение на необходимое нам });
// Цепляемся на конец выполнения функции 'interface.Window.showOrHide' — из аддона. processor.bind ('post-interface.Window.showOrHide', function (sender, params) { console.log ('Значение в конце выполнения функции: ' + params[0]); }); И таким образом непосредственно в interface.Window.showOrHide теперь «прилетит» false, а не true как изначально планировалось.Или вот так можно совсем прервать выполнение функции:
processor.bind ('interface.Window.showOrHide', function (sender, params) { return false; }); Итог Надеюсь в этот раз у меня лучше вышло показать плюсы вот такого «велосипеда».Ну, а посмотреть и скачать исходники (с небольшими примерами) вышеуказанных библиотек можно здесь: Конечно скрипты далеко не идеальны, и есть идеи по улучшению и оптимизациям (в частности по работе с классами), но это немного позже.