Promises
A Promise is a JavaScript object representing the eventual result of an asynchronous operation, starting in a pending state and later settling as either fulfilled with a value or rejected with an error.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples (like fetch to external APIs) may have limitations. For the best experience:
📬 Real-World Analogy: A Promise is like ordering food at a restaurant :
JavaScript Promises are the foundation of all modern asynchronous programming. Nearly every API you interact with— fetch() , database queries, file I/O, animations, WebSockets, workers, AI inference calls, and mobile frameworks—runs on top of Promises. Mastering Promises is the difference between writing buggy, unpredictable code and building systems that scale smoothly across browsers, servers, frameworks, and real-world applications.
At their core, Promises represent a value that will exist in the future. Beginners think of them as "callbacks but cleaner," but this mindset misses their true power. Promises behave like mini-state machines that move between three states— pending , fulfilled , and rejected —and every .then() creates a new Promise linked by a chain of microtasks.
🔥 Basic Promise Chaining
A Promise chain always returns a new Promise, which allows operations to form asynchronous pipelines. Behind the scenes, JavaScript pushes callback functions into the microtask queue, ensuring they run before rendering or macrotask events like timers.
Output: Start Next Final . Each .then() creates a microtask that executes immediately after the current script finishes.
🔥 Returning Promises vs Returning Values
A critical difference exists between returning a value and returning a Promise inside .then() :
The entire chain waits until the inner Promise completes. This allows clean, readable async pipelines where each step waits for the previous operation.
🔥 Error Propagation — The Most Important Promise Mechanic
If you don't understand error flow, you don't understand Promises. Errors flow down the chain until a .catch() handles them. This allows centralised error handling in large applications.
The powerful insight: Once .catch() runs, the chain becomes "clean" again unless you throw another error.
Output: Caught: First error Recovered . The Promise continues normally after error recovery. This behaviour is essential for retry logic, fallbacks, alternative flows, and graceful degradation.
🔥 Throwing Errors Inside .catch() Creates a New Failure Chain
Output: Handled Something broke Final handler: New error . This propagation system enables multi-phase validation, authentication flows, and structured error pipelines.
🔥 Promise Chaining Enables Data Transformation Pipelines
Here's what the chain achieves: GET user → Parse JSON → Extract ID → GET posts → Parse JSON → Filter published posts → Log results. No nesting. No callback hell. Clean, readable async sequences.
🔥 Running Promises in Parallel (Promise.all)
Promise.all() lets you execute multiple async operations at the same time. It is faster and more efficient than waiting for each Promise step-by-step.
Key features: If any Promise fails → the entire chain rejects. It's perfect for loading dashboards, games, financial data, or startup screens. Much faster than awaiting each request one-by-one.
🔥 Promise.allSettled() — Wait For Everything
Unlike Promise.all() , Promise.allSettled() waits for EVERY Promise to finish, even if some fail:
Used in: analytics batching, bulk database updates, large game state sync, uploading multiple assets (some may fail but progress continues).
🔥 Promise.any() — First Success Wins
Returns the first successful result, ignores failures. Useful for redundancy: multiple CDNs, multiple AI model endpoints, or fallback servers.
This pattern is used by real production apps to stay up even if half their services fail.
🔥 Promise Chaining Patterns for Clean Architecture
Complex apps break their async logic into pipelines. Here is a real-world pattern:
This structure is used everywhere: uploading videos, sending content to LLM models, saving game progress, processing payments, managing user onboarding. Good Promise structure = stable, maintainable, scalable software.
🔥 Throttling Promises (Controlling Load)
Sometimes you can't run everything at once. You may need to limit concurrency to protect an API, your server, your database, your GPU/LLM endpoint, or your user's device.
This pattern is used in: image processing, AI inference batching, uploading multiple videos, e-commerce product updates, database-intensive operations.
🔥 Promise Cancellation Patterns
JavaScript doesn't have built-in Promise cancellation, but you can design cancellation-aware flows using AbortController :
Apps use this to: cancel old search requests, cancel loading screens if user navigates away, cancel long API calls (e.g., AI generation).
🔥 Fallback Pattern
🔥 Retry With Backoff
Used heavily in: AI inference (HuggingFace, OpenAI, Anthropic), unstable network connections, mobile apps, payment processing gateways.
🔥 The Promise Pool Pattern
Used by Cloudflare, AWS Lambda workers, GPU batching for LLMs, web scrapers, and payment processing. A Promise Pool ensures you run N tasks at a time:
This pattern prevents: API rate limit bans, GPU overload, server memory spikes.
🔥 Common Promise Mistakes to Avoid
❌ Anti-Patterns
🔥 The Correct Way to Chain
🔥 AI/LLM Pipeline Pattern
For AI systems, multi-stage processing is essential:
This is how Anthropic, OpenAI, Mistral, Groq maximize GPU throughput and handle real-world failures gracefully.
🎯 Key Takeaways
Practice quiz
What are the three states of a Promise?
- start, running, done
- open, closed, error
- pending, fulfilled, rejected
- waiting, success, retry
Answer: pending, fulfilled, rejected. A Promise begins pending and settles as either fulfilled (with a value) or rejected (with an error).
Which handler runs when a Promise is fulfilled?
- .then()
- .catch()
- .finally()
- .reject()
Answer: .then(). Per the lesson's state table, fulfilled Promises run .then() handlers; rejected ones run .catch().
In a chain, errors flow down until what handles them?
- A .then()
- A try block
- The event loop
- A .catch()
Answer: A .catch(). Errors propagate down the chain until a .catch() handles them, enabling centralized error handling.
After a .catch() returns a value, what happens to the chain?
- It stops permanently
- It becomes 'clean' and continues with following .then()s
- It rejects again
- It restarts from the top
Answer: It becomes 'clean' and continues with following .then()s. Once .catch() recovers, the chain continues normally unless you throw another error.
What does returning a value from a .then() callback do?
- Wraps the value in a Promise for the next .then()
- Ends the chain
- Throws an error
- Skips the next .then()
Answer: Wraps the value in a Promise for the next .then(). Returning a value instantly wraps it in a resolved Promise, passing it to the next .then().
If one Promise in Promise.all([...]) rejects, what happens?
- The others' results are still returned
- It waits and ignores the failure
- The entire Promise.all rejects
- It retries automatically
Answer: The entire Promise.all rejects. Promise.all rejects as soon as any input Promise rejects; for partial results use Promise.allSettled.
How does Promise.allSettled differ from Promise.all?
- It rejects faster
- It waits for every Promise to finish, even failures
- It only takes two Promises
- It returns the first success
Answer: It waits for every Promise to finish, even failures. allSettled waits for all Promises and reports each as fulfilled or rejected, never short-circuiting.
What does Promise.any return?
- All results as an array
- The first rejection
- Always undefined
- The first successful result, ignoring failures
Answer: The first successful result, ignoring failures. Promise.any resolves with the first fulfilled result and ignores rejections — useful for redundant endpoints.
Which is a common Promise anti-pattern the lesson warns about?
- Returning values from .then()
- Forgetting to return inside .then()
- Using .catch() at the end
- Chaining .then() calls
Answer: Forgetting to return inside .then(). Forgetting to return inside .then() yields undefined to the next step and breaks the data flow.
What does JavaScript use to support Promise cancellation?
- Promise.cancel()
- clearPromise()
- AbortController
- setTimeout
Answer: AbortController. There is no built-in cancellation; you design cancellation-aware flows with AbortController and its signal.