
mousemove
, resize
или scroll
, ваша страница может тормозить. Такие события генерируются пачками по много штук в секунду. Если обработчик занимает много времени, браузер может не успевать перерисовывать страницу.Вот что использовать, если сталкиваетесь с такой проблемой:
Throttling
По умолчанию код в обработчике события выполняется при каждой генерации события. Иногда нормально, если этот код будет выполняться не при каждом событии, а, например, раз в 100–200 мс. Чтобы «замедлить» код таким образом, можно использовать утилитный метод
_.throttle
(статья на CSS-Tricks).В каких случаях это подходит: например, если вы при изменении размера браузера перевычисляете лэйаут страницы в JavaScript-коде. Если лэйаут вычисляется долго, можно выполнять вычисления не при каждом событии, а немного реже.
Код «до — после»: https://gist.github.com/iamakulov/9c19f872bbbc05b20904db5a2041cd36#file-throttling-js
passive: true
passive: true
— это флаг, который передаётся в addEventListener
. Он говорит браузеру, что обработчик события пассивный — то есть он никогда не вызовет event.preventDefault()
. За счёт этого браузер может выполнять действие, которое обработчик мог бы отменить, сразу же — не дожидаясь, пока закончит выполняться JS-код. (Описание флага на GitHub)В каких случаях это подходит: в основном для событий прокрутки. На самом деле, флаг был создан именно для этих событий, и я не знаю, приносит ли он пользу для каких-то ещё. Как-нибудь измерю и расскажу.
Но в целом — думаю, можете смело использовать
passive: true
для всех событий, которые не вызывают event.preventDefault
. Хуже не будет, лучше может быть.Код «до — после»: https://gist.github.com/iamakulov/9c19f872bbbc05b20904db5a2041cd36#file-passive-js
Оптимизировать сам код
Посмотрите — может, вместо throttle можно оптимизировать сам код, закешировав часть вычислений. Это будет лучше всего — частота обработки событий будет такая же, а тормозить ничего не будет.
Как оптимизировать — зависит от вас. Если у вас React, и в обработчике событий вы изменяете стейт, можете попробовать отрезать часть дерева рендеринга с помощью shouldComponentUpdate.
Рассчитывайте, что, чтобы не пропускать кадры, обработчик должен занимать не больше 10 мс. Бюджет каждого кадра — 16 мс, и браузеру за этот кадр нужно успеть выполнить не только JS-код. Чтобы проверить, сколько времени занимает ваш обработчик, используйте Web Performance API или вкладку Performance в Chrome DevTools.