Debounce work with setTimeout2() and clearTimeout2()
setTimeout2(id, callback, timeout) is setTimeout with a name. When you call it again with the same id before the time is over, the previous timer is cancelled and replaced: the callback runs once, after the calls stop. It is the usual way to save, reload or recalculate only once when many events arrive together (a burst of changes, typing, a flood of messages).
clearTimeout2(id) cancels the timer of that id and returns true when there was one and false when there was not.
The full form is setTimeout2(id, callback, timeout, limit, a, b, c, d, e): the values after limit are passed to the callback. Do not use limit in total5 0.0.19: the idea is to run the callback at once after limit replacements, but the counter never starts (it is undefined and becomes NaN), so the callback is only ever called when the time is over. The example calls it ten times with a limit of 3 and the callback did not run early.
exports.install = function() {
ROUTE('GET /burst/', burst);
};
async function burst($) {
const log = [];
// three calls with the same id: only the last one runs
setTimeout2('save', () => log.push('first'), 100);
setTimeout2('save', () => log.push('second'), 100);
setTimeout2('save', () => log.push('third'), 100);
// a timer that is cancelled before it runs
setTimeout2('gone', () => log.push('gone'), 100);
const cancelled = clearTimeout2('gone');
const nothing = clearTimeout2('never-set');
// the values after the limit reach the callback
setTimeout2('args', (a, b) => log.push(a + b), 50, 0, 'x', 'y');
// the limit option does not run the callback early
let early = 0;
for (let i = 0; i < 10; i++)
setTimeout2('limited', () => early++, 1000, 3);
const stopped = clearTimeout2('limited');
await new Promise(resolve => setTimeout(resolve, 300));
$.json({ log: log, cancelled: cancelled, nothing: nothing, early: early, stopped: stopped });
}