Throttling и Debouncing: объяснение на примерах

Перевод статьи «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]

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх