TOM.js — особая библиотека, для особых случаев +3


Приветствую всех.
Не знаю на сколько верно я описал данную библиотеку в заголовке, но рассказать я хочу именно о ней.



Что это?


Библиотека TOM.js даёт возможность облегчить такие задачи как:
  • загрузка/подгрузка скриптов/стилей с зависимостями
  • создание/наследование классов
  • перехват функций в пределах приложения

Зачем это если есть аналоги?


Я прекрасно осведомлен о том что есть всяческие RequireJS, klass.js и прочее, но данная библиотека представляет из себя наработки за несколько лет под конкретные задачи в проекте над которым я работаю.

Например функционал перехвата вызова функций я нигде не встречал, но нам в проекте необходим был данный функционал для разработки расширений на все случаи жизни, а позже и для других задач. А там уже и создание классов с нужным набором параметров и функций, ну и конечно же загрузчик файлов созданный с учётом специфики нашего проекта.

TOM.boot — загрузка модулей и скриптов с зависимостями


Изначально это была небольшая библиотека, которая за 4 года была переписана уже несколько раз из-за неприятных багов с зависимостями. В последний раз была попытка реализации загрузки при помощи RequireJS, с небольшой «надстройкой», но в итоге эта «надстройка» получилась такой закрученной (да и о зависимостях у RequireJS свои понятия) что оказалось легче реализовать свой загрузчик но уже не допуская тех ошибок которые были в прошлых реализациях.

Что-же умеет данная часть библиотеки?


  • Загрузка модулей и скриптов


    Для загрузки «модулей» (о них я расскажу немного ниже) и скриптов можно использовать около 5 вариаций вызовов

    1 способ, задача: загрузить /libraries/jquery/jquery.boot.js и /libraries/scroll/scroll.boot.js
    TOM.boot.load( 'libraries/*', [ 'jquery', 'scroll' ], function( ){ } );
    

    2 способ, задача: загрузить /jquery/jquery.boot.js
    TOM.boot.load( '*', 'jquery',  function( ){ } );
    

    3 способ, задача: загрузить /jquery.boot.js
    TOM.boot.load( '', 'jquery', function( ){ } );
    

    4 способ, задача: загрузить /jquery.js
    TOM.boot.load( '', 'jquery.js', function( ){ } );
    

    5 способ, задача: загрузить code.jquery.com/jquery-1.12.0.min.js
    TOM.boot.load( '', 'https://code.jquery.com/jquery-1.12.0.min.js', function( ){ } );
    

    Как можно понять по примерам — структура функции вызова следующая:
    TOM.boot.load( 'путь к скрипту/модулю', 'имя файла/модуля' {строка или массив}, 'callback по окончанию загрузки' );
    

    Логика подбора полного пути тут проста — если в имени нет расширения значит мы загружаем модуль (*.boot.js), если есть — то конкретный файл. А * (звёздочка) в пути подставляет в данное место имя модуля/файла, что позволяет сохранять понятную структуру директорий и файлов в больших приложениях.

  • Загрузка скриптов из модуля с учётом зависимостей


    Для начала следует разобрать что такое «модуль» в понимании данной библиотеки.
    Модуль — это файл *.boot.js в котором прописаны конкретные файлы и их зависимости от других «модулей» и скриптов.

    Содержимое *.boot.js выглядит следующим образом:
    TOM.boot.initiate( 'button', [
    	{ file: '*.style.css' }, // загружаем button.style.css
    	{ file: '*.interface.js' }, // загружаем button.interface.js
    	{ file: '*.core.js', require: '*.interface.js' }, // загружаем button.core.js с зависимостью от button.interface.js
    	{ file: 'testButton.core.js', require: [ 'jquery', '*.core.js' ] } // загружаем testButton.core.js с зависимостями
    ] );
    

    Здесь структура имеет следующий вид:
    TOM.boot.initiate( 'имя модуля', 'список объектов загружаемых файлов с параметрами' );
    

    Ну а сами объекты загружаемых файлов имеют следующую структуру:
    • file — имя загружаемого файла, где * (звёздочка) подставляет имя модуля
    • require — зависимость (список зависимостей) как от файлов текущего модуля, так и от других модулей
    • initialize — функция (список функций) которую следует выполнить после загрузки скрипта
    • main — булевая переменная указывающая что все в данном модуле зависят от данного файла


TOM.processor — перехват функций выполняемых внутри приложения


На самом деле перехват функций будет происходить только там где Вам это необходимо, только в тех объектах которые вы «пропроксируете».
В нашем проекте например имеется 3 объекта которые прописаны в window и с которыми мы работаем, это наши так-называемые «области видимости»: api, core, interface именно с ними мы и работаем, потому только их и проксируем.

TOM.js по умолчанию создаёт core и interface, но работать с ними или нет это личное дело каждого.

Как с этим работать?


  • Проксирование


    Первое что необходимо сделать — это произвести «проксирование» нужных объектов подобным образом:
    TOM.processor.proxy( core );
    TOM.processor.proxy( interface );
    

    Суть проксирования проста до безобразия — проходим по объекту и обёртываем функции определённым видом (добавляем pre-callback и post-callback).

  • Обработка/Перехват вызова функций


    После обработки нужных объектов вызванные внутри них функции- можно обрабатывать подобным образом:
    // Обработка вызова создания кнопки
    TOM.processor.bind( 'pre-core.test.addTestButton', function( sender )
    {	
    	// Если мы не хотим на самом деле создавать кнопку - прерываем её создание
    	if( !confirm( 'Действительно создать кнопку?' ) )
    	{
    		return false;
    	}
    } );
    

    Обработчик имеет такую структуру:
    TOM.processor.bind( '{pre или post}-имя функции вызова которой ждём', 'callback функция', 'параметры' );
    

    • pre или post — это обработка «до вызова» оригинала функции, или после — соответственно
    • параметры — это объект с настройками данного обработчика
      • stage — аналог pre/post в имени функции
      • label — «метка» по которой мы сможем снять именно этот обработчик, не затрагивая другие
      • priority — добавлять данный обработчик в начало или в конец очереди?

  • Другие возможности


    Помимо непосредственно возможности добавления и снятия «обработчиков», можно так-же:
    • «возбуждать фейковые события»:
      TOM.processor.signal( 'момент запуска (pre/post)', 'имя функции', 'объект вызывающий функцию', 'аргументы' );
    • производить единоразовую обработку события:
      TOM.processor.one( 'перечень тех же аргументов что и в TOM.processor.bind' );


TOM.classes — создание и наследование классов


Данная часть библиотеки обыгрывает стандартный подход к созданию и наследованию классов в стандартном JavaScript, но с большим количеством нюансов и наработок.

  • Как создать/унаследовать класс?


    • 1й способ
      TOM.classes.create(
      	 'область видимости / объект в котором нужно создавать класс',
      	 'имя создаваемого класса',
      	 'класс от которого нужно наследоваться', 
      
      	// Функция конструктор
      	function constructor( )
      	{
      	},
      	
      	// -- Дальше идут функции в виде аргументов -- //
      
      	function foo( )
      	{
      	},
      
      	function bar( )
      	{
      	}
      )
      
    • 2й способ
      TOM.classes.create(
      	 'область видимости / объект в котором нужно создавать класс',
      	 'имя создаваемого класса',
      	 'класс от которого нужно наследоваться', 
      
      	// Функция конструктор
      	function constructor( )
      	{
      	},
      	
      	// Функции в массиве или объекте
      	[
      		function foo( )
      		{
      		},
      
      		function bar( )
      		{
      		}
      	]
      )
      
    • 3й способ — такой-же как и — но в массиве находится ещё и конструктор


  • Какие особенности данного скрипта?


    Кроме совместимости с TOM.processor, в созданных классах более-менее адекватно работает вызов функций из родителя, при помощи:
    this.__parentCall__( ); // Вызов функции родителя исходя из arguments.callee
    this.__parentFunction__( 'имя функции', 'аргументы' ); // Вызов функции по имени
    

    И много других мелочей.
    Примечание: Я знаю что arguments.callee это плохо, и оно не работает в strict mode, но пока удобной замены не придумал.


Дэмо страница: tredsnet.github.io/TOM
GitHub репозиторий: github.com/tredsnet/TOM

Библиотека конечно не очень подготовлена для публикации, не «вычухан» код, не убраны лишние комментарии и заметки, где-то возможно нестандартное поведение (так как тестировалось только на нашем проекте). Но всему своё время, возможно и в таком виде библиотека будет кому-то полезна, а в случае заинтересованности пользователей — возможно и развитие в нужном направлении.

Спасибо что дочитали до конца. Буду рад любым комментариям, но прошу не забывать что библиотека создавалась под конкретные нужды, конкретного проекта.
Будет ли Вам полезна данная библиотека?

Проголосовало 134 человека. Воздержался 91 человек.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.




К сожалению, не доступен сервер mySQL