Дросселирование и устранение дребезга в Javascript
20 мая 2022 г.Дросселирование и устранение дребезга — хорошие методы повышения производительности вашего веб-сайта.
Давайте представим, что у нас есть прослушиватель событий при перемещении мыши или прокрутке, и у вас есть обратный вызов, который выполняет некоторые вычисления, занимает много времени, и эта функция вызывается много раз во время перемещения мыши, прокрутки или других событий. Конечно, эта ситуация может сильно снизить производительность вашего сайта.
Другой пример, у нас есть ввод для поиска, и мы помещаем слушателя в событие ввода и на каждую вводную букву делаем HTTP-запросы. Давайте представим, что мы хотим найти предметы, используя слово ==blueberry==. Как только мы введем «==b==», будут запущены HTTP-запросы, также «==l==», также «==u==», также «==b==» и т. д. Каждая введенная буква будет запустить HTTP-запрос. Но в целом мы хотим иметь всего 1 HTTP-вызов, когда слово будет полностью набрано.
Оба метода могут помочь с этими проблемами, и каждый из них работает немного по-разному и используется в разных случаях. Итак, давайте рассмотрим примеры.
Мы хотим создать указатель мыши, который следует за курсором пользователя, с небольшим смещением от курсора. В общем, задача несложная, так что давайте.
Код очень простой, так что давайте посмотрим:
Берем контейнер (это может быть любой элемент, например body), также я подготовил div для указателя, добавил несколько стилей (можно добавить любой стиль, который вы хотите), а сердце логики — JS.
В JS я просто добавляю слушателя в контейнер. Любые прослушиватели событий, передайте объект ==event==, который содержит много полезной информации, и для нашей цели у нас есть доступ к шнурам курсора мыши в то время, когда этот обратный вызов был запущен. Зная эти шнуры, мы просто добавляем некоторое смещение и меняем положение нашего указателя.
Давайте посмотрим, сколько времени будет срабатывать наш обратный вызов. Для этого я буду перемещать указатель мыши из начального левого угла экрана в конец.
Конечно, это не идеальная методика измерения, но в целом дает понимание. В моем случае, как мы видим, это 55 раз.
Можем ли мы уменьшить количество вызовов этой функции, но оставить прежний функционал? Конечно. Давайте познакомимся с техникой дросселирования.
Дросселирование определяет, сколько функций можно вызывать в течение определенного времени. Например, вызывать какую-то функцию не чаще 1 раза в миллисекунду, например вызывать функцию раз в 100 миллисекунд или раз в 50 миллисекунд.
Существует множество реализаций дросселирования и устранения дребезга, которые вы можете найти, и такие библиотеки, как lodash, также содержат их. Итак, давайте выберем любую реализацию дросселя и используем ее для нашего примера.
Как я уже упоминал, это всего лишь одна из многих других реализаций, если вам интересно, вы можете найти другие и попытаться сравнить их, но это не цель этой статьи.
Теперь давайте используем его для нашего указателя.
Здесь мы говорим, что функция onMouseMove будет вызываться один раз в 30 миллисекунд. Проверяем результат:
После газа и 30 миллисекунд количество вызовов нашей функции равно 32, а не 55, как было в первый раз. Вызовы функций сократились почти в 2 раза. Вы можете играть с величиной задержки, в некоторых случаях вы можете поставить большую сумму, в других случаях это может быть плохой результат, и вы должны использовать меньшее время задержки, так что это зависит от вашей задачи.
Но наверняка, если у вас есть какие-то сложные вычисления или HTTP-запросы в ваших обратных вызовах, дроссель может помочь вам уменьшить количество вызовов функций.
Теперь поговорим о следующем задании. Представьте, что мы хотим скрыть этот указатель после того, как пользователь перестанет двигать указатель мыши через 3 секунды. Но если он остановится всего на 1-2 секунды и продолжит движение, мы не должны скрывать указатель мыши.
Первое решение, которое вы можете придумать, заключается в том, что мы можем просто добавить setTimeout с 3 секундами, и все. Но проблема в том, что он скроет указатель через 3 секунды, независимо от того, перемещает ли пользователь свой курсор или нет.
В нашем случае мы хотим сделать тайм-аут в 3 секунды только после того, как пользователь перестанет двигать мышью. И если пользователь останавливает мышь всего на 1 или 2 секунды, а после продолжает движение, мы не хотим скрывать указатель, пока пользователь не остановится более чем на 3 секунды.
Давайте посмотрим на пример ниже:
Как видите, наш указатель мыши исчезает, только если пользователь не двигает мышь более 3 секунд.
Как это сделать?
Debounce — это метод, который запускает функцию только до тех пор, пока не пройдет определенное количество времени. Как мы видим на примере, мы можем задержать нашу функцию на определенное время, но если это время меньше, наш таймаут продлевается.
Давайте проверим код:
Как реализация дросселирования, debounce также имеет множество различных реализаций, поэтому я нашел только одну из них:
Также я создал простые функции hideMousePointer и showMousePointer:
showMousePointer Я запускаю внутри onMouseMovie на тот случай, если указатель был скрыт ранее.
hideMousePointer Я использую внутреннюю функцию устранения дребезга в качестве обратного вызова и устанавливаю 3 секунды в качестве задержки.
И да, здесь в примере мы объединяем троттлинг и дебаунс вместе. Но это не обязательно. Вы можете использовать оба из них независимо. Вместо дросселированияMouseMove мы можем использовать простой mouseMove в нашем примере, для скрытия/отображения результат будет таким же.
Другим популярным примером использования debounce является поле ввода, где вы вводите ключевые слова для поиска чего-либо, также вы помещаете прослушиватель событий ==input==, и внутри слушателя вы отправляете HTTP-запрос с входным текстом. Но мы не хотим отправлять HTTP для каждой входной буквы. Мы хотим подождать небольшое количество времени, пока пользователь не перестанет писать, и только после отправки 1 HTTP-запроса с целым словом вместо множества HTTP-вызовов для каждой буквы.
В общем, все, повторим еще раз:
Дросселирование — это метод, который можно использовать, когда вам нужно запустить функцию 1 раз в каждый конкретный интервал времени, вызывать функцию один раз в 100 миллисекунд или один раз в 50 миллисекунд.
Debounce — это метод, который заставляет функцию не вызываться снова, пока не пройдет определенное количество времени. Например, делать HTTP-запрос только тогда, когда пользователь перестает что-то писать или только после того, как прокрутка страницы была остановлена более чем на 3 секунды.
Я надеюсь, что теперь вы лучше понимаете разницу между этими двумя методами и можете найти их применение в своих проектах.
Оригинал