Good API documentation tells callers how to use the library correctly and what it cannot guarantee. Our limit caps active mapper calls from 1 to 64. It does not promise CPU parallelism, constant total memory, a timeout, retries, or interruption of a noncooperating callback.
The rejection boundary is especially important: the pool waits for already active callbacks. If a callback ignores abort and never settles, neither does the pool. A caller needing a deadline must design the work itself to stop or settle, not only race an unrelated timer and pretend the underlying resource disappeared.
Input order determines output positions; first observed failure determines the primary failure. A single phrase such as “fast and safe” does not communicate either rule. Pair each guarantee with a small example and a test location.
For extensions, change the contract before the implementation. Streaming results would need a new ordering and buffering policy. Supporting async iterables would require serializing next requests and waiting for async cleanup. Those are separate APIs, not a one-line promise to support everything.
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.
const guarantees = [
"bounded active calls",
"input-order results",
"cooperative abort"
];
console.log(guarantees.join("; "));Check your prediction
bounded active calls; input-order results; cooperative abort Replace vague promises with observable rules
A useful guarantee names a trigger, outcome and limit. After first observed mapper failure, the pool stops pulling but waits for active callbacks: that sentence specifies both behavior and settlement. Finite input and eventually settling callbacks are assumptions the caller supplies. Bounded concurrency alone promises neither constant result memory nor interruption of uncooperative work.
| Boundary or case | What to inspect |
|---|---|
| Order | Output follows input positions rather than completion |
| Cancellation | Signal requests cooperation and cannot undo side effects |
| Ownership | Items remain shared references and collected results consume growing storage |
Write a counterexample to instant cancellation or constant memory, then state the narrower guarantee this API actually supports. Link it to a distinguishing test. Specify an extension’s new ordering and cleanup policy before promising streaming or asynchronous sources.
Your turn
Documenting Library Limits: practise
Implement validateLimit(value) returning the input if it is an integer 1–64, otherwise throwing RangeError. Print 1 and 64, then rejected for 0. Keep the assertion about rejection outside its try block.
// This is a boundary contract, not an automatic performance recommendation.Hint 1: the idea
Both endpoints are inclusive.
Hint 2: a first step
Check integer status and the lower and upper bounds.
Show one solution
function validateLimit(value) {
if (!Number.isInteger(value) || value < 1 || value > 64) {
throw new RangeError("Invalid limit");
}
return value;
}
console.log(validateLimit(1));
console.log(validateLimit(64));
let rejected = false;
try {
validateLimit(0);
} catch (error) {
rejected = error instanceof RangeError;
}
if (!rejected) {
throw new Error("Expected rejection");
}
console.log("rejected");1
64
rejectedExplain 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
Draft a README paragraph for a caller with slow, occasionally failing callbacks. Include settlement timing, cleanup ownership and retained output. Then propose one extension and list the extra tests required before advertising it.
Completion is saved in this browser only. It does not measure mastery.