A buffer that batches then flushes
Firing a request for every click, keystroke or log line floods the network. The standard fix is a buffer with two triggers: flush as soon as enough items pile up, and flush anyway once the oldest item has waited long enough.
Implement a BatchBuffer class. new BatchBuffer(onFlush, options) takes a callback and an options object { size, waitMs }, defaulting to size 10 and waitMs 100. add(item) appends an item to the pending batch and returns the number of items pending afterwards. If adding brings the pending count up to size, flush immediately and synchronously, before add returns — so add returns 0 in that case. Otherwise, if this item is the first of a new batch, start a timer for waitMs milliseconds; adds after that must not restart the timer, so the batch is sent waitMs after its first item rather than after its last. flushNow() sends whatever is pending straight away and returns how many items it sent; when nothing is pending it does not call the callback and returns 0. pending() returns how many items are waiting.
Flushing means calling onFlush(items) once with a plain array of the pending items in the order they were added, then clearing the pending list and cancelling any timer. The callback is never called with an empty array.
Examples
const sent = [];
const b = new BatchBuffer((items) => sent.push(items), { size: 3, waitMs: 1000 });
b.add(1); b.add(2);
b.add(3); // triggers a sync flush
sent; // [[1, 2, 3]]
b.pending(); // 0Reaching the batch size flushes inside the add call.
const sent = [];
const b = new BatchBuffer((items) => sent.push(items), { size: 10, waitMs: 20 });
b.add("a"); b.add("b");
// 20ms later: sent === [["a", "b"]]An unfilled batch flushes waitMs after its first item.
What it has to do
- Reaching
sizeitems flushes synchronously inside theaddcall. - A batch that never fills is flushed
waitMsafter its first item. - Later adds do not restart the timer.
flushNow()returns the number sent and does nothing when nothing is pending.onFlushreceives the items in the order they were added, and is never called with an empty array.
Notes
- The 'wait from first item' rule is what gives latency guarantees. If each add restarted the timer, a steady stream of events would hold a batch open forever.
- Only start a timer when there is not one already. That single conditional is the whole difference between first-item-wait and last-item-wait semantics.
- Always clear the timer inside
flushNow(), otherwise a flush-by-size will still fire a redundant timer flush later with nothing in the buffer.
Stuck? The javascript course covers everything this challenge needs.
- 1.a full batch flushes inside the add call
- 2.an unfilled batch flushes after the wait
- 3.later adds do not restart the timer
- 4.flushNow reports what it sent and ignores an empty buffer
- 5.splits a run of items into full batches plus a remainder
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.