Реализовать throttle(fn, limit)
Реализуйте throttle(fn, limit), возвращающую обёртку с ограничением частоты: fn запускается не чаще раза в limit мс, как бы часто ни вызывалась обёртка. Первый вызов выполняется сразу (передний фронт); вызовы внутри окна игнорируются. Сохраните this и передайте все аргументы в fn.
function throttle(fn, limit) {
// ваш код здесь
}
Допишите реализацию.
Хранить в замыкании lastRun (метку времени), стартующую так, чтобы первый вызов прошёл. На каждом вызове вычислять now = Date.now(); если now - lastRun >= limit, установить lastRun = now и запустить fn.apply(this, args), иначе игнорировать вызов. Это ограничивает fn одним запуском за окно limit по переднему фронту, сохраняя this и аргументы.
- ✗Путать throttle с debounce — throttle ограничивает частоту, debounce ждёт паузу
- ✗Инициализировать
lastRunтак, что самый первый вызов ошибочно пропускается - ✗Терять
this/аргументы, вызываяfn()напрямую вместоfn.apply(this, args)
- →Как добавить завершающий вызов, чтобы последнее обращение не терялось?
- →Почему версия с передним фронтом срабатывает на первом вызове сразу?
Решение
Хранить метку времени последнего запуска; выполнять fn, только если окно limit истекло.
function throttle(fn, limit) {
let lastRun = -Infinity;
return function (...args) {
const now = Date.now();
if (now - lastRun >= limit) {
lastRun = now;
fn.apply(this, args);
}
};
}
Как это работает
lastRun хранит время последнего фактического запуска fn и живёт в замыкании между вызовами. Стартовое значение -Infinity гарантирует, что самый первый вызов сразу проходит проверку (передний фронт).
На каждом вызове сравниваем now - lastRun с limit. Если прошло достаточно времени — обновляем lastRun и запускаем fn.apply(this, args), сохраняя контекст и аргументы. Иначе вызов просто игнорируется. Так fn выполняется максимум раз в limit мс, как бы часто обёртку ни дёргали.