Реализовать debounce(fn, delay)
Реализуйте debounce(fn, delay), возвращающую обёртку с устранением дребезга: fn запускается лишь через delay мс после ПОСЛЕДНЕГО вызова, а любой вызов внутри этого окна отменяет ожидающий запуск и перезапускает таймер. Сохраните this и передайте все аргументы в fn. При 8 быстрых вызовах обёртки fn выполнится один раз.
function debounce(fn, delay) {
// ваш код здесь
}
Допишите реализацию.
Хранить timeoutId в замыкании. Возвращённая функция вызывает clearTimeout(timeoutId), отменяя ожидающий запуск, затем timeoutId = setTimeout(...), планируя fn через delay. Внутри таймера вызвать fn.apply(this, args), чтобы сохранить this и передать аргументы. Выживает лишь таймер последнего вызова, поэтому fn запускается один раз после прекращения активности.
- ✗Путать debounce с throttle — debounce ждёт паузу, а не фиксированную частоту
- ✗Забывать
clearTimeout, из-за чего каждый вызов срабатывает после своей задержки, а не только последний - ✗Терять
this/аргументы, вызываяfn()напрямую вместоfn.apply(this, args)
- →Как добавить опцию переднего фронта, чтобы срабатывать и на первом вызове?
- →Как замкнутый
timeoutIdвыживает между отдельными вызовами?
Решение
Хранить timeoutId в замыкании; на каждом вызове отменять предыдущий таймер и ставить новый.
function debounce(fn, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
Как это работает
timeoutId живёт в замыкании и переживает отдельные вызовы обёртки. На каждом вызове clearTimeout отменяет ранее запланированный запуск, а setTimeout ставит новый таймер на delay. Пока вызовы идут чаще, чем раз в delay, таймер постоянно сбрасывается, и fn не выполняется.
Когда вызовы прекращаются, последний таймер доживает до конца и запускает fn ровно один раз. fn.apply(this, args) сохраняет контекст this вызывающего и передаёт все аргументы. Стрелочная функция в setTimeout не имеет своего this, поэтому this берётся из обёртки.