Сегодня, стало более ли менее стандартом использование синтетических событий в современных js фреймворках, нежели обычный addEventListener. Но, как же работают эти события? В данной статье, я постараюсь на примере клика в Cample.js версии 3.2.0-beta.1 рассказать об этом.

Прежде всего, когда говорится о работе с событиями, очевидно, что речь заходит о конструкции addEventListener, которая выглядит следующим образом:

element.addEventListener("событие", "функция", useCapture или options);

Но, так ли это быстро? Как оказалось, это не быстро из‑за специфики работы.

Когда речь заходит о фреймворках, важна каждая секунда работы, ведь это в теории тысячи сэкономленных часов использования сайтов или веб‑приложений.

Поэтому, нужно было придумать альтернативу, которая заменит такой подход на более быстрый.

Самая банальная идея событий на сайте — что‑то выдаёт действие будь то мышка или клавиатура, а javascript вызывает функцию, которая на это событие срабатывает. Тогда, возникает необходимость в двух вещах — обрабатывать событие и где‑то его хранить. Но, где?

Если отойти немного назад, то надо вспомнить о том, что DOM элемент является, можно сказать, объектом со своими свойствами. У него есть текст, у него есть следующий элемент и предыдущий и т. д. Так вот, что если функцию хранить в самом элементе (объекте) DOM? Это сразу решает две проблемы: как понять, «на что вызывать функцию?» и «где её хранить?».

То-есть, грубо говоря, как это выглядит:

<div></div>["клик"] = функция;

Соглашусь, что это выглядит странно, но, если получить элемент через getElementById, к примеру, и вывести его в консоль как объект, то действительно, это будет выглядеть как‑то так, что мы присвоили свойство тегу в HTML (понятное дело, что элементу в DOM) со значением функции.

Так вот, остаётся вторая проблема, а как, собственно, обрабатывать событие клика зная, что у нас в DOM элементе есть функция. Это тоже достаточно интересный вопрос, но реализация очевидно будет связанна с addEventListener, потому что этот метод способен обрабатывать события.

Возникает тогда вопрос, а куда его ставить, если на Element в DOM будет медленно? Тут есть тоже достаточно крутое решение. Можно поставить обработку события прямо на документ, а в свойствах принимать target, по которому кликнули. Как это будет выглядеть в теории в javascript:

document.addEventListener("click", (e)=>...);

Таким образом, есть функция, которая срабатывает, когда кликается на элемент в document, а есть место, куда кликается. Так вот, это место клика как раз может являться объектом DOM, в который было вложено свойство с функцией срабатывания.

К примеру, в Cample.js, обработка будет выглядеть следующим образом:

const newEach = each("new-each",
    ()=>["val"],
    `<div id="el" :click="{{importedData.fn(data)}}" 
    key="{{index}}">{{data}}</div>`
);

Для элемента div с id «el», будет присвоена функция, которая приходит из импортированных данных. Если по документу будет кликнуто мышкой, тогда данная функция будет вызвана.

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

Всем большое спасибо за прочтение данной статьи!

Комментарии (7)


  1. dcooder
    14.10.2023 13:50
    +1

    Было бы неплохо подробнее расписать механизмы, за счет которых реализуется ваша оптимизация. Я так полагаю, что вы перехватываете событие на фазе погружения? тогда почему не указали, что передаете в addEventListener параметр capture: true? Это же по сути та основа, на которой стоит вся ваша оптимизация. Или вы используете какие-то другие особенности работы событий в DOM?


    1. antonmak1 Автор
      14.10.2023 13:50

      capture true не используется в реализации.


    1. antonmak1 Автор
      14.10.2023 13:50

      Событие перехватывается и вместо дефолтной фазы всплытия срабатывает кастомная для клика


    1. dcooder
      14.10.2023 13:50

      Тогда не понятно, за счет чего достигается более быстрый отклик? Если использовать addEventListener без capture: true, то событие перехватиться на стадии всплытия. А на фазе всплытия событие достигает document позже, чем целевого элемента.


  1. ALapinskas
    14.10.2023 13:50
    +1

    Когда речь идет о производительности, хочется видеть хоть какие-то бенчмарки.


    1. antonmak1 Автор
      14.10.2023 13:50
      -3

      Есть бенчмарки в js-framework-benchmark репозитории


  1. Duck7722
    14.10.2023 13:50

    Но, так ли это быстро? Как оказалось, это не быстро из-за специфики работы.