16. Implement retry(fn, retries, delay) — Retry a Promise

medium

Retry-with-backoff is a real-world async pattern (flaky network calls) and a clean recursion-over-promises question.

The idea

Try fn. On rejection, either give up (out of retries → rethrow) or wait, then recurse with one fewer retry and a doubled delay. Doubling is exponential backoff — it stops a struggling server from getting hammered.

Follow-ups

  • "Cap the delay?" → Math.min(delay * 2, maxDelay).
  • "Jitter?" → add a random fraction to avoid synchronized retries (the thundering herd).
  • "Only retry some errors?" → take a shouldRetry(err) predicate.
  • "Abort support?" → thread an AbortSignal and reject early if it fires.

What to practice

Write the recursive version, then add a maxDelay cap and random jitter.

More questions

index.js
function retry(fn, retries = 3, delay = 100) {
  // fn returns a Promise; resolve on success, give up after `retries`
}

let n = 0;
retry(() => (++n < 3 ? Promise.reject('fail') : Promise.resolve('ok')))
  .then(console.log); // "ok" on the 3rd attempt

Tests

Test Code

Enter JavaScript that runs after your solution. It should return a value or a Promise.