A batch generator groups an iterable into arrays of at most size items. It validates size as a positive integer, yields a full batch when ready, then yields a final short batch if there is one. Empty input yields nothing.
Each yielded batch must be a distinct array. Reusing and clearing the same array would let later work change batches that a caller already kept. This is an ownership contract, not just a formatting detail.
The generator’s body starts on consumption, so invalid size is reported when next is called or a loop begins, not necessarily at the function call itself. Document that timing. You can choose an eager wrapper if callers need validation at construction; do not imply your generator validates sooner than it does.
Predict, run, and explain
Write the output and trace the important state changes before checking it. Then run the program. Each editor is independent. Async examples end with main() so this editor waits for their work.
function* values() {
yield 1;
yield 2;
yield 3;
}
const iterator = values();
console.log(iterator.next().value);
console.log([...iterator].join(","));Check your prediction
1
2,3 Acceptance cases before you code
Write a small test plan before implementing batch boundaries and ownership. These cases extend the brief; they are not a second worked solution. Predict the expected behavior independently, then test through the public function. A good ordinary example and a good boundary example should catch different possible mistakes.
| Case to try | What your result should demonstrate |
|---|---|
| Empty source | Yield no batch |
| Final short group | Yield it once without a trailing empty group |
| Retained batches | Changing one must not change another batch array |
After the core task passes, deliberately break one rule and identify the case that notices it. Restore the implementation and explain the failure in terms of the contract, not the number of assertions. If a case requires a concept you have not recalled, revisit the relevant lesson before opening the solution.
Your turn
Checkpoint: Lazy Batches: practise
Implement batches(values, size). For [1,2,3,4,5] and size 2, print 1,2 then 3,4 then 5. Do not yield an empty final batch. Retained batches must not share the same array.
// Validate inside the generator, collect a batch, then replace the batch array after yielding.Hint 1: the idea
A fresh array after each yield preserves earlier batches.
Hint 2: a first step
After a full batch is yielded, assign a new empty array rather than clearing the old one.
Show one solution
function* batches(values, size) {
if (!Number.isInteger(size) || size < 1) {
throw new RangeError("Invalid size");
}
let batch = [];
for (const value of values) {
batch.push(value);
if (batch.length === size) {
yield batch;
batch = [];
}
}
if (batch.length) {
yield batch;
}
}
for (const batch of batches([1, 2, 3, 4, 5], 2)) {
console.log(batch.join(","));
}1,2
3,4
5Explain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?
Change it and test it
Test empty input, size 1, a size larger than the source and invalid sizes. Keep two output arrays and assert they are different references. Then use a generator with finally as the source and break early to verify cleanup propagates.
Completion is saved in this browser only. It does not measure mastery.