Как сбросить кеш через секунду и обновлять значение при вызове функции
Что проверяют
Умеете ли вы написать небольшую утилиту с состоянием и временем: мемоизацию с TTL. Смотрят на замыкания, работу таймеров и на то, подумали ли вы о граничных случаях. Следом обычно просят поддержать аргументы и асинхронную функцию.
Как отвечать
Сначала уточните условие: секунда считается от момента записи значения или продлевается при каждом обращении. Это два разных кеша, с фиксированным и со скользящим сроком жизни.
Самое надёжное решение обходится без таймеров: храните значение вместе со временем записи и проверяйте срок при вызове.
function withTtl(fn, ttl = 1000) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
const hit = cache.get(key);
const now = performance.now();
if (hit && now - hit.at < ttl) return hit.value;
const value = fn(...args);
cache.set(key, { value, at: now });
return value;
};
}Что стоит проговорить:
- нет висящих таймеров:
setTimeoutна каждый ключ держит замыкание и засоряет очередь, а проверка при чтении почти ничего не стоит; - монотонное время:
performance.now()не прыгает при переводе системных часов, в отличие отDate.now(); - асинхронный случай: кешируйте сам промис, тогда параллельные вызовы в пределах секунды получат один запрос. При отклонении промиса удаляйте запись, иначе закешируется ошибка;
- память: протухшие ключи удаляйте при обращении или редкой чисткой, иначе
Mapрастёт бесконечно.
Если по условию значение нужно именно сбрасывать по таймеру, покажите clearTimeout перед новым setTimeout и объясните, чем эта схема отличается от проверки при чтении.
Где спотыкаются
Не уточняют, что значит «обновлять при вызове», и пишут скользящий срок там, где ждали фиксированный, или наоборот.
Полагаются на точность setTimeout. Он гарантирует только «не раньше», а в фоновой вкладке браузер троттлит таймеры, и сброс может случиться заметно позже секунды.
Берут JSON.stringify(args) как ключ и не оговаривают ограничения: объекты с разным порядком полей дают разные ключи, функции и undefined теряются. Проговорите это и предложите WeakMap для одного объектного аргумента.