Как стать автором
Обновить

Решение задач Front End с интервью. Throttle

Уровень сложностиПростой
Время на прочтение2 мин
Количество просмотров6.2K

Методы замедления (Throttling) служат для контроля того, сколько раз мы разрешаем выполнение функции за определенный период времени. Обычно throttling реализуется через Higher Order Function. Функция - обертка должна контролировать, чтобы callback функция вызывалась не чаще одного раза каждые X миллисекунд. Callback функция вызывается немедленно и не может быть вызвана снова в течение оставшегося времени ожидания.

Задача на реализацию Throttling часто дается на интервью и на первый взгляд кажется тривиальной, но и тут есть свои нюансы.

Давайте реализуем функцию throttle, которая принимает функцию callback и время ожидания. Вызов throttle() должен возвращать новую функцию, которая будет вызывать внутри себя callback функцию в соответствии с описанным выше поведением.

Примеры использования

let i = 0;
function increment() {
i++;
}
const throttledIncrement = throttle(increment, 100);
// t = 0: Call throttledIncrement(). i is now 1.
throttledIncrement(); // i = 1
// t = 50: Call throttledIncrement() again.
//  i is still 1 because 100ms have not passed.
throttledIncrement(); // i = 1
// t = 101: Call throttledIncrement() again. i is now 2.
//  i can be incremented because it has been more than 100ms
//  since the last throttledIncrement() call at t = 0.
throttledIncrement(); // i = 2

Решение

Существует два основных способа решения данной задачи - с использованием setTimeout или с использованием Date.now()

Решение через Date.now()

/**
 * @callback func
 * @param {number} wait
 * @return {Function}
 */
export default function throttle(func, wait) {
  let lastCallTime = null;
    return function (...args) {
        const now = Date.now();
        const passed = now - lastCallTime;
        if(passed > wait){
            func.apply(this, args);
            lastCallTime = Date.now();
        }
    }
}

Рассмотрим решение через Date.now(). Решение довольно тривиальное - мы запоминаем последнее время вызова, и используем его для определения, нужно ли вызывать функцию func, или нет. На мой взгляд - данное решение предпочтительнее, поскольку оно не добавляет новый вызов в Event Loop.

Решение через setTimeout()

/**
 * @callback func
 * @param {number} wait
 * @return {Function}
 */
export default function throttle(func, wait) {
  let shouldThrottle = false
    return function (...args) {
        if(!shouldThrottle){
            func.apply(this, args);
            shouldThrottle = true;
            setTimeout(() => {
                shouldThrottle = false;
            }, wait);
        }
    }
}

Тут тоже все довольно тривиально - мы используем setTimeout для выставления актуального значения флага shouldThrottle. На основании текущего значения флага, мы определяем, нужно или нет вызывать функцию func.

На что стоит обратить внимание?

Будьте внимательны с тем, чтобы функция корректно работала с параметром this.

Вызов исходной функции func должен сохранять исходный указатель this. Поэтому:

  • Arrow-функции нельзя использовать для объявления внутренней функции.

  • Вызов исходной функции через func(...args) также нельзя использовать.

Для вызова исходной функции, предпочтительнее использовать func.apply или func.call, в зависимости от Ваших предпочтений (с появлением spread оператора они по большей части эквивалентны).

В следующей статье, я хочу разобрать решение задачи с Leetcode 2636, Promise Pool. Похожую (немного усложненную) задачу давали в Yandex на Two Days Offer в этом году.

Теги:
Хабы:
Всего голосов 5: ↑3 и ↓2+4
Комментарии4

Публикации

Истории

Работа

Ближайшие события

19 марта – 28 апреля
Экспедиция «Рэйдикс»
Нижний НовгородЕкатеринбургНовосибирскВладивостокИжевскКазаньТюменьУфаИркутскЧелябинскСамараХабаровскКрасноярскОмск
24 апреля
VK Go Meetup 2025
Санкт-ПетербургОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань
14 мая
LinkMeetup
Москва
5 июня
Конференция TechRec AI&HR 2025
МоскваОнлайн
20 – 22 июня
Летняя айти-тусовка Summer Merge
Ульяновская область