Перевод статьи «Throttling vs Debouncing».
Такие события, как ‘click’, ‘type’, ‘scroll’, ‘drag’ и т. п. могут использоваться для запуска функции обработчика так часто, что это ухудшит производительность веб-приложения. Чтобы ограничить нежелательные вызовы функций и поддерживать производительность на должном уровне, мы используем полифиллы, такие как throttling и debouncing.
Давайте попробуем разобраться в работе этих двух алгоритмов, а для для этого рассмотрим простую аналогию.
Допустим, ваша бабушка пообещала покупать вам мороженое в любое время, когда бы вы ее ни попросили. Единственное условие — между покупками мороженого должно проходить как минимум два дня. Сегодня вы попросили мороженое и уже получили его.
Throttling
Прошел день, и вы просите у бабушки еще одно мороженое. Она отвечает, что вы можете получить свое мороженое завтра или послезавтра (если захотите), но не сегодня, потому что два дня еще не прошло. А правило же простое: максимум одно мороженое каждые два дня.
Это — throttling вызова функции askForIcecream()
. Все неуместные, преждевременные вызовы просто игнорируются. Технически, когда вы производите throttling функции, вы контролируете, чтобы она не вызывалась повторно до истечения определенного времени с момента последнего выполнения.
Debouncing
А теперь представьте, что ваша бабушка куда более строгая. Вы уже получили мороженое вчера, а сегодня просите его опять, нарушая правила! Она отсылает вас прочь и говорит, чтобы в ближайшие два дня вы к ней и не подходили со своими хотелками.
То есть, вы нарушили правило, и теперь наказаны: можно было бы получить мороженое завтра, но получите позже. Каждый преждевременный запрос на мороженое откладывает его получение на два дня.
Это — debouncing вызова функции askForIcecream()
. Все слишком рано сделанные запросы влекут за собой дополнительную задержку.
Технически, когда вы производите debouncing функции, вы обеспечиваете обязательный интервал после последнего поступившего вызова. Суть в том, что каждый раз, когда кто-то пытается запустить функцию до положенного времени, добавляется новая задержка.
Что ж, давайте теперь углубим наше понимание предмета на более реальных примерах. Как throttling и debouncing применяются в веб-приложениях?
Пример 1 (debouncing): окно поиска
Допустим, у нас есть веб-приложение, в котором на странице продуктов перечислены товары из разных категорий. Как сделать так, чтобы на странице отображались только релевантные продукты из миллиона доступных? Верно: дайте пользователю окно поиска.
Это поле ввода с кнопкой «Искать» или «Перейти». Вы вводите название продукта, нажимаете кнопку, и запускается функция getResults()
, которая выдает вам список продуктов, соответствующих вашей строке поиска.
Я не вижу причин ограничивать количество вызовов getResults()
. Давайте подумаем о другом сценарии.
Вашим пользователям пригодятся подсказки — список возможных вариантов в выпадающем списке. Когда пользователь начинает вводить название искомого продукта, ему начинают предлагать варианты того, что он, вероятно, имел в виду. По мере ввода текста варианты меняются, их диапазон сужается. Такое есть даже у Google на странице поиска.
Если задуматься, можно прийти к выводу, что здесь используется какое-то из событий, связанных со вводом текста. Какие возможности в этом плане есть в JavaScript? У нас есть onKeyPress
, onKeyUp
и onKeyDown
.
В нашем случае можно использовать onKeyPress
и запускать функцию getSuggestions()
каждый раз, когда пользователь вводит символ в поле поиска.
Но если подумать, становится ясно, что запускать getSuggestions()
после ввода каждого символа может быть не очень хорошо. Куда лучше запускать эту функцию, когда пользователь вводил-вводил, а потом остановился на некоторое время (скажем, на 2 миллисекунды). Технически говоря, мы хотим задерживать (debounce) вызов getSuggestions()
на 2 мс.
Пример 2 (throttling): изменение размеров окна
Допустим, вы хотите, чтобы, когда пользователь меняет размер окна, контент вашей страницы менялся.
Конечно, это можно сделать при помощи CSS и медиа-запросов. Но давайте предположим, что вы хотите как-то обнаруживать изменение размера окна. Причем хотите делать это оптимальным образом.
Обычно, когда вы подключаете функцию прослушивания событий к событию «resize» в объекте «window», при перетаскивании обработчик срабатывает при каждом передвижении курсора.
Это может быть неоптимальным для вашего случая. Скажем, вам нужно, чтобы какая-то дорогостоящая логика внутри функции обработчика событий запускалась не чаще раза в секунду.
Технически в таких случаях вы делаете тротлинг этой функции, ограничивая возможность ее вызова. Все события «resize» должны игнорироваться до истечения 1 секунды с момента последнего вызова обработчика событий.
Сценариев, в которых для сохранения производительности вам может пригодиться одна из вышеупомянутых стратегий, довольно много. Но я надеюсь, что эта статья помогла вам понять теорию, и вы сможете применить полученные знания на практике.
[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]