Сегодня, стало более ли менее стандартом использование синтетических событий в современных 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)
ALapinskas
14.10.2023 13:50+1Когда речь идет о производительности, хочется видеть хоть какие-то бенчмарки.
dcooder
Было бы неплохо подробнее расписать механизмы, за счет которых реализуется ваша оптимизация. Я так полагаю, что вы перехватываете событие на фазе погружения? тогда почему не указали, что передаете в addEventListener параметр capture: true? Это же по сути та основа, на которой стоит вся ваша оптимизация. Или вы используете какие-то другие особенности работы событий в DOM?
antonmak1 Автор
capture true не используется в реализации.
antonmak1 Автор
Событие перехватывается и вместо дефолтной фазы всплытия срабатывает кастомная для клика
dcooder
Тогда не понятно, за счет чего достигается более быстрый отклик? Если использовать addEventListener без capture: true, то событие перехватиться на стадии всплытия. А на фазе всплытия событие достигает document позже, чем целевого элемента.