Как реализовать debounce?
надо было написать функцию debounce, которая должна принимать функцию и время задержки, а возвращать модифицированную функцию. Пример:
let counter = 0;
const fn = () => {
counter++;
};
const debouncedFn = debounce(fn, 200);
debouncedFn(); // первый вызов
setTimeout(debouncedFn, 100); // вызов через 100 мс после последнего вызова
// первый вызов был заблокирован, второй ожидает окончания таймера
setTimeout(debouncedFn, 200); // вызов через 100 мс после последнего вызова
// второй вызов был заблокирован, третий ожидает окончания таймера
setTimeout(debouncedFn, 300); // ...
setTimeout(debouncedFn, 400); // после этого вызова не следует других вызовов
// только этот вызов сработает, т.к. после него прошло 200 мс и других вызовов не было
console.log(counter); // 1
Мой код:
const debounce = (fn, debounceTime) => {
let count = -Infinity;
let res;
return function() {
const end = Date.now();
if (end - count >= debounceTime) {
count = end;
res = fn.apply(this, arguments);
}
return res;
};
};
Не проходит тест "должна блокировать вызовы функции в течение времени задержки, пока функция вызывается снова ранее, чем прошло время задержки", что не так?
Ответы (2 шт):
Если я правильно понял из описания, то вам нужна функция, которая будет выполняться через некоторое время после вызова, а если еще раз функцию вызвали, то отменять предыдущий вызов и запускать заново.
let counter = 0;
const fnс = () => {
counter++;
};
// Каждый следующий вызов отменяет предыдущий, если он ожидает выполнения
const debounce = (fn, debounceTime) => {
let timer;
return function() {
clearInterval(timer);
timer = setTimeout(fn, debounceTime);
};
};
const debouncedFn = debounce(fnс, 200);
debouncedFn(); // первый вызов
setTimeout(debouncedFn, 100); // вызов через 100 мс после последнего вызова
// первый вызов был заблокирован, второй ожидает окончания таймера
setTimeout(debouncedFn, 200); // вызов через 100 мс после последнего вызова
// второй вызов был заблокирован, третий ожидает окончания таймера
setTimeout(debouncedFn, 300); // ...
setTimeout(debouncedFn, 400); // после этого вызова не следует других вызовов
// только этот вызов сработает, т.к. после него прошло 200 мс и других вызовов не было
console.log('Ждем окончания');
setTimeout(() => {
console.log('CNT', counter); // 1
}, 1000);
Если надо, что бы сначала вызывалась, а потом запускался таймер, не позволяющий выполнить функцию в течении некоторго времени, то фукнция должна иметь вид примерно такой:
const debounce = (fn, debounceTime) => {
let isWait = false;
return function() {
if (!isWait) {
isWait = true;
fn();
setTimeout(() => isWait = false, debounceTime);
}
};
};
Всё у вас правильно, кроме следующего момента: если вы решаете не вызывать функцию, вы возвращаете результат её последнего вызова. Тестирующая система такое решение не примет. Правильно возвращать undefined если функцию вызывать рано:
const debounce = (fn, debounceTime) => {
let count = -Infinity;
return function() {
const end = Date.now();
let res = undefined;
if (end - count >= debounceTime) {
count = end;
res = fn.apply(this, arguments);
}
return res;
};
};
Ещё мелочь: если запоминать не время вызова а время когда вызывать fn будет можно, то можно немного упростить код:
const debounce = (fn, delay) => {
let deadline = 0;
return () => {
const now = Date.now();
if (now < deadline) {
return undefined;
}
deadline = now + delay;
return fn.apply(this, arguments);
};
};