Вернуться к уроку

Вызов не чаще чем в N миллисекунд

важность: 5

Напишите функцию debounce(f, ms), которая возвращает обёртку, которая откладывает вызов f на ms миллисекунд.

«Лишние» вызовы перезаписывают предыдущие отложенные задания. Все аргументы и контекст – передаются.

Например:

function f() { ... }

let f = debounce(f, 1000);

f(1); // вызов отложен на 1000 мс
f(2); // предыдущий отложенный вызов игнорируется, текущий (2) откладывается на 1000 мс

// через 1 секунду будет выполнен вызов f(1)

setTimeout( function() { f(3) }, 1100); // через 1100 мс отложим вызов еще на 1000 мс
setTimeout( function() { f(4) }, 1200); // игнорируем вызов (3)

// через 2200 мс от начала выполнения будет выполнен вызов f(4)

Упрощённо можно сказать, что debounce возвращает вариант f, срабатывающий не чаще чем раз в ms миллисекунд.

Открыть песочницу с тестами для задачи.

function debounce(f, ms) {

  let timer = null;

  return function (...args) {
    const onComplete = () => {
      f.apply(this, args);
      timer = null;
    }

    if (timer) {
      clearTimeout(timer);
    }

    timer = setTimeout(onComplete, ms);
  };
}

function f(x) { alert(x) }
let f = debounce(f, 1000);

f(1); // вызов отложен на 1000 мс
f(2); // предыдущий отложенный вызов игнорируется, текущий (2) откладывается на 1000 мс

// через 1 секунду появится alert(2)

setTimeout( function() { f(3) }, 1100); // через 1100 мс отложим вызов еще на 1000 мс
setTimeout( function() { f(4) }, 1200); // игнорируем вызов (3)

// через 2200 мс от начала выполнения появится alert(4)

Вызов debounce возвращает функцию-обёртку. Все необходимые данные для неё хранятся в замыкании.

При первом вызове обертки в значении переменной timer находится null и происходит вызов setTimeout.

Этот вызов во-первых отложит выполнение декорируемой функции на ms миллисекунд, а во-вторых установит в качестве значения time числовой идентификатор, который позволит обнулить отложенное задание при последующих вызовах.

Открыть решение с тестами в песочнице.