I wrote a small debounce utility for an input handler, but when I trigger it several times quickly, it sometimes logs an older value instead of the most recent one. What is wrong with this implementation?
function debounce(fn, wait) {
let timer, lastArgs;
return function (...args) {
lastArgs = args;
if (timer) clearTimeout(timer);
timer = setTimeout(fn(lastArgs), wait);
};
}
const log = debounce((v) => console.log(v), 200);
setTimeout(fn(lastArgs), wait) calls fn immediately and stores its return value as the timer callback, so rapid calls race against already-executed work.
Your fn(lastArgs) line is the culprit MechaPrime pointed at, and there’s a second snag because it passes the whole args array as one value, so defer a wrapper like setTimeout(() => fn(.lastArgs), wait) if you want the newest call to survive the stampede.
@ArthurDent mentioned the whole args array issue too, so if fn expects normal parameters you want setTimeout(() => fn(.lastArgs), wait) or the latest call arrives wrapped wrong.