Хуки JS в LS, краткое руководство для тех, кто запутался

Сегодня обратился за помощью товарищей всем известный разработчик avadim — не может вникнуть в дзен механизма хуков, которые работают на бэкенде (ЖС). Поэтому решил оформить этот ответ в виде краткого поста — может кому нибудь будет полезно.

Вступление


Механизм делегирования кода ЖС в ЛС можно осуществлять такими наиболее часто употребляемыми методами в зависимости от поставленной задачи:

  1. Переопределить всю функцию (атата!)
    В своем коде просто переопределить весь метод:
    ls.MODULE.METHOD = function (param1, param2) { /* party hard */ }
    

    Желательно не использовать данный подход, он показан для примера.
  2. Механизм хуков
  3. Механизм маркеров

Рассмотрим кратко каждый из приемов.

1. Хуки


Объявление хука (места, где может быть выполнен произвольный код)

Пример кода:
ls.hook.run ('js_hook_super_name', [obj, block], this);


Создает запись для выполнения кода __здесь__ (где он расположен), вторым параметром передается массив параметров ([obj, block]) и указатель контекста (this). В твоем случае (для avadim ) это просто контекст так описан (где-то написано thisArg = this выше в коде).

вот, а теперь этот хук можно перехватить с помощью плагина и вызвать свой код:

Использование хука (вызов кода в место, где объявлен хук)

Пример кода:
ls.hook.add ('js_hook_super_name', function (obj, block) { /* code here */ });


Хук на который цепляемся (js_hook_super_name), а также анонимная функция, в которую передаются параметры (obj, block), которые объявлены в самом хуке. Третий возможный параметр — приоритет. Контекст в этой анонимной функции будет тот, на который указывает третий параметр объявления хука (в данном примере — this)

2. Маркеры


Когда я написал статью, я понял что, возможно, описание маркеров нужно было начинать с возможности инжекта кода, но, пожалуй, оставлю текст таким как есть. Не останавливайтесь если что-то не совсем понятно — читайте далее. Маркеры и их параметры я расписал очень детально.

Маркер очень похож на работу хуков за исключением того что сама функция будет модифицирована в месте маркера или в начале функции (в зависимости от параметров вызова инжекта).

Объявление маркера (места, где может быть модифицирована оригинальная функция)

Пример кода:
ls.hook.marker ('SomePlace');


Создает дополнительное место в функции (где он объявлен) для выполнения кода. Не обязателен. Маркера может и не быть вовсе, но и в такую функцию код добавить можно — в самое её начало (после открывающей скобки ({). Понятней станет после прочтения вызова инжекта кода (см. ниже).

А теперь как этот код может быть модифицирован:

Инжект кода в начало функции или место, где в ней объявлен маркер

Пример кода:
ls.hook.inject ([ls.MODULE, 'METHOD'], function () { /* i`m INSIDE of func and maybe on marker place */ });


Первый параметр вызова:
[ls.MODULE, 'METHOD']

— имя функции куда нужно инжектить код. Может быть: строкой ('ls.MODULE.METHOD', полной функцией (ls.MODULE.METHOD) или массивом ([ls.MODULE, 'METHOD']), где первый параметр — модуль, второй — строка, название метода.

Второй параметр вызова — собственно код и третий параметр (строка, не обязательный) — указание имени маркера (в данном примере — 'SomePlace'), куда вставлять свой код в функции (первый параметр вызова). Если не указать третий параметр, то код (2-й параметр вызова) будет вставлен в начало функции (1-й параметр вызова) сразу после открывающей скобки ({), в противном случае код будет помещен на место маркера ('SomePlace') в этой функции (1-й параметр вызова).

Другими словами: код в анонимной функции (2-й параметр вызова) будет «перенесен» в место маркера или на начало функции как будто он там и был написан с самого начала. Это позволяет управлять ходом обработки функции в т.ч. сделать return false чтобы прервать выполнение метода если нужно. Хук (см. выше п. 1 вступления) прервать выполнение метода не может, только оперировать с набором параметров, которые переданы в функцию хука.

Итог


В ЛС существует два нормальных механизма дополнения ЖС кода своим функционалом и один метод хардкора, который использовать не стоит т.к. исчезает полная совместимость с другими плагинами.

Возможно, это кому-то поможет писать более правильные плагины без делегирования функционала шаблона (я бы вообще запретил в каталоге шаблоны с делегированием, но иногда без делегирования — никак)

Хочу заметить что замечательный механизм хуков в ЛС придумал пользователь 1d10t и впервые сообщил здесь.

UPD: Топик дополнен описанием маркеров и исправлены пара неточностей в описании.

UPD 2: Здесь можно найти отредактированную версию этой статьи.
Зачастую поездка на поезде выходит быстрее, чем на самолете. Это связанно с большой удаленностью аэропортов и долгим ожиданием вылета. Сэкономить время можно на заказе такси в аэропорт Домодедово, которое доставит вас точно в срок перед вылетом.

8 комментариев

avatar
Информацию о маркерах добавить?
  • ort
  • 0
avatar
добавил. расписал детально
avatar
Слушайте, парни, я чел не гордый, не хотите в моем топике подробно откомментить, так хоть тут ответьте: НАФИГА?

Нафига два принципиально разных механизма использовать для одного и того же действия в одном функциональном методе? Просто потому что так когда-то решили и ничо менять не будем?

Для меня странно, что абсолютно произвольная модификация нативного кода на лету — это считается нормально, а переопределение метода (банальнейшая вещь!) называется хардкодом и не рекомендована. Почему? И что мешает в хуках сделать обработку возвращаемого значения?
avatar
И что мешает в хуках сделать обработку возвращаемого значения?
идея интересна. просто нужно собраться, решится на это дело (понимая что версия в которой будут внесены эти изменения будет снова не совсем совместима), но зато будет единый механизм.
avatar
Я правильно понимаю, что если на хук вешается несколько функций, то они будут выполняться последовательно? И каков в этом случае порядок вызова функций? По порядку «цепляния»?
avatar
третьим параметром можно указать приоритет
avatar
Спасибо, разобрался, наконец. Но Макс прав — в текущей реализации надо обязательно вместе рассматривать и хуки, и маркеры. И мне это — не нравится. Поэтому предлагаю довести идею (которая сама по себе хороша) до логического конца: livestreet.ru/blog/wishlist/12341.html
avatar
Супер, спасибо за объяснение! Инжекты спасли — можно цепляться почти за что угодно независимо от наличия хуков или маркеров, очень мощная фича.
  • NPC
  • +1
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.