Promises & Promise Combinators

Promise হলো state machine — pending, fulfilled, rejected

~45 min Advanced 18 practice problems Live runner

1. The Three States

pending fulfilled (value) rejected (reason) resolve(v) reject(e) Figure 22.1 — once a Promise leaves pending, it cannot change state again.

2. Creating a Promise

create.js
const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        if (Math.random() < 0.5) resolve("ok!");
        else reject(new Error("failed"));
    }, 100);
});

p.then(v => console.log("value:", v))
 .catch(e => console.log("error:", e.message))
 .finally(() => console.log("done"));
নতুন Promise তৈরি করতে new Promise((resolve, reject) => {...})। ফলাফল pending থেকে fulfilled (resolve) বা rejected (reject) হয় — শুধু একবার।

3. Chaining

Each .then returns a new Promise. Whatever you return from a handler becomes the next Promise's value. Throw inside any handler and the chain skips to .catch.

chain.js
Promise.resolve(2)
    .then(n => n + 1)
    .then(n => n * 10)
    .then(n => { if (n > 20) throw new Error("too big"); return n; })
    .then(console.log)
    .catch(e => console.log("caught:", e.message));
Always return inside a .then If you forget return, the next .then sees undefined and fires immediately — async results vanish. Use async/await next module to make this impossible.

4. The Four Combinators

MethodResolves withRejects when
Promise.allArray of all valuesAny one rejects (fail-fast)
Promise.allSettledArray of {status, value/reason}Never
Promise.raceFirst to settle (resolve or reject)If first to settle rejects
Promise.anyFirst to fulfillAll reject (AggregateError)
combinators.js
const ok    = (v, ms = 10) => new Promise(r => setTimeout(() => r(v), ms));
const fail  = (e, ms = 10) => new Promise((_, j) => setTimeout(() => j(e), ms));

(async () => {
    console.log("all:",
        await Promise.all([ok(1), ok(2), ok(3)]));

    console.log("allSettled:",
        await Promise.allSettled([ok(1), fail("x"), ok(3)]));

    console.log("race:",
        await Promise.race([ok("slow", 100), ok("fast", 10)]));

    console.log("any:",
        await Promise.any([fail("x"), ok("y")]));
})();

5. Promisify a Callback API

promisify.js
const promisify = fn => (...args) =>
    new Promise((res, rej) =>
        fn(...args, (err, data) => err ? rej(err) : res(data)));

const readDelay = (key, cb) => setTimeout(() => cb(null, `value of ${key}`), 10);
const readP = promisify(readDelay);

readP("foo").then(console.log);

6. Common Bugs

  • Forgetting return inside a .then — the chain races ahead
  • Swallowing errors by missing the final .catch
  • Mixing then/catch with the wrong order — .then(handle).catch(...) only catches errors from handle too, but not from inside .then(success, fail) form
  • Wrapping a promise in new Promise — that's the "Promise constructor anti-pattern"
  • Resolving with a Promise — that's fine; it gets unwrapped automatically

7. Glossary (শব্দকোষ)

TermMeaningবাংলায়
PromiseState machine: pending → fulfilled (value) or rejected (reason).State machine: pending → fulfilled / rejected।
resolve / rejectFunctions that move a Promise from pending into a settled state.Promise-কে settle করার দুটি function।
SettledEither fulfilled or rejected — no longer pending.Pending নয় — fulfilled বা rejected অবস্থা।
.thenAdds a callback for fulfillment; returns a new Promise.Fulfillment-এ callback; নতুন Promise ফেরত দেয়।
.catchShorthand for .then(undefined, onReject)..then(undefined, onReject)-এর সংক্ষেপ।
.finallyAlways runs once the chain settles.Chain settle হলেই চলে — cleanup-এ ব্যবহৃত।
Promise.allResolves with all values; fails fast on any rejection.সব value-র array; যেকোনো rejection-এ fail।
Promise.allSettledAlways resolves with status objects.সব result সংগ্রহ — কখনো reject হয় না।
Promise.raceSettles with the first promise to settle.প্রথম settle-হওয়া Promise-এর সাথে settle।
Promise.anyResolves with the first fulfilled; rejects only if all reject.প্রথম fulfilled; সব fail হলে AggregateError।
মূল কথা: Promise একটি state machine — settle হয় শুধুমাত্র একবার। Chain-এ প্রতিটি .then নতুন Promise দেয়; ভেতরে throw করলে chain skip করে .catch-এ চলে যায়। চারটি combinator (all/allSettled/race/any) মুখস্থ থাকলে যেকোনো async pattern সাজানো যায়।

8. Practice Problems

  1. Create a Promise that resolves to "hi" after 50 ms.
    ✨ Show Answer
    a1.js
    new Promise(r => setTimeout(() => r("hi"), 50)).then(console.log);
  2. Chain three increments using .then.
    ✨ Show Answer
    a2.js
    Promise.resolve(0)
        .then(n => n + 1)
        .then(n => n + 1)
        .then(n => n + 1)
        .then(console.log);
  3. Catch a rejected Promise and print its message.
    ✨ Show Answer
    a3.js
    Promise.reject(new Error("oops"))
        .catch(e => console.log("caught:", e.message));
  4. Use Promise.all to await three timers.
    ✨ Show Answer
    a4.js
    const wait = ms => new Promise(r => setTimeout(() => r(ms), ms));
    Promise.all([wait(10), wait(20), wait(30)]).then(console.log);
  5. Use Promise.allSettled with one rejected Promise.
    ✨ Show Answer
    a5.js
    Promise.allSettled([
        Promise.resolve(1),
        Promise.reject("x"),
        Promise.resolve(3)
    ]).then(console.log);
  6. Race two timers and print the faster.
    ✨ Show Answer
    a6.js
    const wait = (v, ms) => new Promise(r => setTimeout(() => r(v), ms));
    Promise.race([wait("slow", 200), wait("fast", 20)]).then(console.log);
  7. Use Promise.any with one fail and one success.
    ✨ Show Answer
    a7.js
    Promise.any([
        Promise.reject("x"),
        Promise.resolve("ok")
    ]).then(console.log);
  8. Build a delay(ms) Promise utility.
    ✨ Show Answer
    a8.js
    const delay = ms => new Promise(r => setTimeout(r, ms));
    delay(30).then(() => console.log("after 30ms"));
  9. Implement timeout(promise, ms) that rejects if the inner promise is too slow.
    ✨ Show Answer
    a9.js
    const timeout = (p, ms) => Promise.race([
        p,
        new Promise((_, rej) => setTimeout(() => rej(new Error("timeout")), ms))
    ]);
    
    const slow = new Promise(r => setTimeout(() => r("done"), 200));
    timeout(slow, 50).catch(e => console.log(e.message));
  10. Show that throwing inside a .then jumps to .catch.
    ✨ Show Answer
    a10.js
    Promise.resolve(1)
        .then(() => { throw new Error("boom"); })
        .then(() => console.log("skipped"))
        .catch(e => console.log("caught:", e.message));
  11. Promisify setTimeout as sleep(ms) using new Promise.
    ✨ Show Answer
    a11.js
    const sleep = ms => new Promise(r => setTimeout(r, ms));
    (async () => { await sleep(20); console.log("slept"); })();
  12. Run two promises in parallel and sum results.
    ✨ Show Answer
    a12.js
    const ok = (v, ms) => new Promise(r => setTimeout(() => r(v), ms));
    Promise.all([ok(10, 20), ok(15, 10)])
        .then(([a, b]) => console.log(a + b));
  13. Why does Promise.all fail-fast?
    ✨ Show Answer

    Answer: By design — once any input rejects, the aggregate has nothing useful to deliver, so it rejects immediately and lets you handle the failure. If you want to wait for every result and inspect successes and failures separately, use Promise.allSettled.

  14. Demonstrate that resolving with a Promise unwraps it automatically.
    ✨ Show Answer
    a14.js
    const nested = Promise.resolve(Promise.resolve(42));
    nested.then(console.log);   // 42, not a Promise
  15. Use .finally to run cleanup whether the chain succeeds or fails.
    ✨ Show Answer
    a15.js
    Promise.resolve(1)
        .then(console.log)
        .finally(() => console.log("cleanup ok"));
    
    Promise.reject("x")
        .catch(e => console.log("err:", e))
        .finally(() => console.log("cleanup err"));
  16. Build a retry helper: retry(fn, n).
    ✨ Show Answer
    a16.js
    async function retry(fn, n) {
        let last;
        for (let i = 0; i < n; i++) {
            try { return await fn(); }
            catch (e) { last = e; }
        }
        throw last;
    }
    
    let i = 0;
    retry(() => ++i < 3 ? Promise.reject("nope") : Promise.resolve("ok"), 5)
        .then(console.log);
  17. Show the "forgot to return inside .then" bug.
    ✨ Show Answer
    a17.js
    const wait = ms => new Promise(r => setTimeout(() => r(ms), ms));
    
    // BUG — forgot return
    Promise.resolve().then(() => { wait(50); })
        .then(v => console.log("bug got:", v));   // undefined!
    
    // FIX — return the promise
    Promise.resolve().then(() => wait(50))
        .then(v => console.log("fix got:", v));
  18. Why is mixing then(success, fail) with .catch confusing? In one paragraph.
    ✨ Show Answer

    Answer: The two-arg form .then(success, fail) only catches rejections from the upstream Promise — it cannot catch errors thrown inside its own success handler. A trailing .catch can. Mixing both makes it ambiguous which errors land where; prefer .then(success).catch(...) or async/await + try/catch.

Summary — Module 22

A Promise is a state machine — pending until it settles, then permanently fulfilled or rejected. Chain with .then/.catch/.finally. Combine with all, allSettled, race, any. Always return inside .then; always end the chain with .catch.

Promise একটি state machine। .then chain এবং চারটি combinator মনে রাখুন। return ভুলবেন না।

Next Module → async/await — সিনট্যাক্স sugar Promise-এর উপর।