Реализовать функцию debounce
Условие
Напишите функцию debounce(fn, delay), которая откладывает вызов переданной функции fn до тех пор, пока не пройдёт delay миллисекунд с момента последнего вызова.
Требования
-
Функция должна принимать два аргумента:
fn— функция, вызов которой нужно отложитьdelay— задержка в миллисекундах
-
Возвращаемая функция должна:
- Сбрасывать таймер при каждом новом вызове
- Вызывать оригинальную функцию только после истечения задержки
- Корректно передавать аргументы в оригинальную функцию
Пример использования
const debouncedLog = debounce((message) => console.log(message), 300);
debouncedLog("Привет"); // Не выведется
debouncedLog("Мир"); // Через 300мс выведет "Мир"
Бонус
Добавьте метод cancel() для отмены отложенного вызова.
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение функции debounce
Что такое debounce?
Debounce — это техника оптимизации, которая откладывает выполнение функции до тех пор, пока не пройдёт определённое время с момента последнего вызова. Это критически важно при обработке часто вызываемых событий (изменение input, скролл, resize), чтобы избежать множественных ненужных вычислений.
Реализация базовой версии
function debounce(fn, delay) {
let timeoutId;
return function debounced(...args) {
// Очищаем предыдущий таймер
clearTimeout(timeoutId);
// Устанавливаем новый таймер
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
С методом cancel() и улучшениями
function debounce(fn, delay) {
let timeoutId;
const debounced = function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
// Метод отмены
debounced.cancel = () => {
clearTimeout(timeoutId);
};
// Метод немедленного вызова
debounced.flush = () => {
clearTimeout(timeoutId);
fn.apply(this);
};
return debounced;
}
TypeScript версия
function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): ((...args: Parameters<T>) => void) & { cancel: () => void; flush: () => void } {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
const debounced = function(this: ThisParameterType<T>, ...args: Parameters<T>) {
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
debounced.cancel = () => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
};
debounced.flush = () => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
fn.apply(this);
}
};
return debounced as any;
}
Примеры использования
// Поиск при вводе
const search = debounce((query) => {
console.log("Ищу:", query);
}, 300);
input.addEventListener("input", (e) => search(e.target.value));
// Обработка resize
const handleResize = debounce(() => {
console.log("Размер изменился");
}, 500);
window.addEventListener("resize", handleResize);
// Отмена
const submit = debounce(() => {
console.log("Отправляю форму");
}, 1000);
submit();
submit.cancel(); // Вызов не произойдёт
Ключевые моменты
- Контекст (this): используем
.apply(this, args)для сохранения контекста вызова - Аргументы: используем rest-параметры
(...args)для захвата всех аргументов - Сброс таймера:
clearTimeout()отменяет предыдущий вызов перед установкой нового - Замыкание: timeoutId сохраняется в замыкании для сохранения состояния между вызовами
- cancel(): даёт возможность отменить запланированный вызов
- flush(): позволяет немедленно выполнить функцию, очистив таймер
Различие между debounce и throttle
Частая ошибка — путать debounce с throttle. Debounce выполняет функцию один раз после периода спокойствия, а throttle выполняет функцию максимум один раз за интервал времени. Выбор зависит от сценария: debounce — для поиска/автосохранения, throttle — для скролла/ресайза.