Promises and Asynchronous APIs

Model eventual results with promises and consume them safely with async/await.

Lesson content

🎯 Goal By the end of this lesson, you'll understand: What is a Promise? Why do we use Promises? Promise States Creating and Using Promises .then() , .catch() , .finally() Asynchronous APIs Real-world examples Interview questions What is a Promise? A Promise is an object that represents the future result of an asynchronous operation. The result may be: Success ✅ Failure ❌ Simple Definition: A Promise is a guarantee that a value will be available now or in the future. Real-Life Example 📦 Imagine ordering a product online. Order Product │ ▼ Order Processing │ ├────────► Delivered ✅ │ └────────► Cancelled ❌ When you place the order, you don't receive the product immediately. You receive a promise that you'll get the result later. Why Do We Need Promises? Without Promises (Callback Hell) loginUser (() => { getOrders (() => { getPayment (() => { sendEmail (() => { console . log( "Done" ); }); }); }); }); Hard to read. With Promises loginUser () . then( getOrders ) . then( getPayment ) . then( sendEmail ) . then(() => console . log( "Done" )) . catch( console . error); Much cleaner. Promise States Every Promise has 3 states . Promise │ ┌────────┴────────┐ │ │ Pending Completed │ ┌────────┴────────┐ │ │ Fulfilled ✅ Rejected ❌ State Meaning Pending Task is still running Fulfilled Task completed successfully Rejected Task failed Creating Your First Promise const promise = new Promise (( resolve , reject ) => { const success = true ; if ( success ) { resolve ( "Payment Successful" ); } else { reject ( "Payment Failed" ); } }); Using .then() promise . then( result => { console . log( result ); }); Output Payment Successful Using .catch() const promise = new Promise (( resolve , reject ) => { reject ( "Something went wrong" ); }); promise . catch( error => { console . log( error ); }); Output Something went wrong Using .finally() Runs whether the Promise succeeds or fails. promise . then( result => console . log( result )) . catch( error => console . log( error )) . finally(() => { console . log( "Finished" ); }); Output Finished (or the result/error first, then "Finished" ) Complete Example const order = new Promise (( resolve , reject ) => { setTimeout (() => { resolve ( "Pizza Delivered" ); }, 2000 ); }); order . then( result => { console . log( result ); }) . catch( error => { console . log( error ); }); Output (After 2 Seconds) Pizza Delivered Promise Flow Create Promise │ ▼ Pending │ ▼ Success? ─────────────► Yes │ │ ▼ ▼ Reject() Resolve() │ │ ▼ ▼ catch() then() Promise Chaining Promise . resolve( 10 ) . then( num => num * 2 ) . then( num => num + 5 ) . then( num => console . log( num )); Output 25 Each .then() receives the previous result. What are Asynchronous APIs? An Asynchronous API performs work in the background without blocking JavaScript. Examples include: Reading files Writing files Database queries HTTP requests Timers Example: Reading a File const fs = require ( "fs/promises" ); async function readData () { const data = await fs . readFile( "test.txt" , "utf8" ); console . log( data ); } readData (); The file is read asynchronously. Example: Fetch API fetch ( "https://jsonplaceholder.typicode.com/users/1" ) . then( response => response . json()) . then( data => console . log( data )) . catch( error => console . log( error )); The network request happens in the background. Example: setTimeout() console . log( "Start" ); new Promise ( resolve => { setTimeout (() => { resolve ( "Task Finished" ); }, 2000 ); }) . then( console . log); console . log( "End" ); Output Start End Task Finished Promise vs Callback Callback Promise Nested code Flat code Hard error handling Easy error handling Callback Hell Promise Chaining Older approach Modern approach Promise vs Async/Await Promise getUser () . then( user => getOrders ( user . id)) . then( orders => console . log( orders )) . catch( console . error); Async/Await async function loadData () { try { const user = await getUser (); const orders = await getOrders ( user . id); console . log( orders ); } catch ( err ) { console . log( err ); } } loadData (); Both work, but async/await is usually easier to read. Real-Life Example 🏦 Bank Loan Apply for Loan │ ▼ Bank Reviews │ ┌─────┴─────┐ │ │ ▼ ▼ Approved Rejected A Promise behaves exactly like this. Common Promise Methods Method Purpose .then() Handle success .catch() Handle errors .finally() Run after completion Promise.resolve() Create a resolved Promise Promise.reject() Create a rejected Promise Promise.all() Wait for all Promises Promise.race() First Promise wins Promise.allSettled() Wait for all, regardless of success or failure Promise.any() First successful Promise wins Interview Question What is the output? console . log( "Start" ); Promise . resolve( "Hello" ) . then( console . log); console . log( "End" ); Output Start End Hello Reason The .then() callback is executed asynchronously after the current synchronous code completes. Best Practices ✅ Return Promises from asynchronous functions. ✅ Always handle errors using .catch() or try...catch . ✅ Prefer async/await for complex asynchronous flows. ✅ Use Promise.all() when multiple independent asynchronous tasks can run in parallel. ❌ Don't create unnecessary nested .then() chains. Common Mistakes ❌ Forgetting to Return a Promise fetchData () . then(() => { getUser (); }) . then( console . log); If getUser() returns a Promise, return it. ✅ Correct fetchData () . then(() => { return getUser (); }) . then( console . log); Ignoring Errors fetchData () . then( data => console . log( data )); If the Promise rejects, the error is unhandled. ✅ Better fetchData () . then( data => console . log( data )) . catch( err => console . error( err )); Key Points ✅ A Promise represents the future result of an asynchronous operation. ✅ Promise states are Pending , Fulfilled , and Rejected . ✅ .then() handles success. ✅ .catch() handles errors. ✅ .finally() runs regardless of success or failure. ✅ Promises help avoid Callback Hell. ✅ Asynchronous APIs allow Node.js to perform non-blocking operations. 🧠 Easy Formula Need async operation? │ ▼ Promise Success? │ Yes ─────► .then() Failure? │ Yes ─────► .catch() Always run? │ ▼ .finally() Pending │ ▼ Fulfilled → .then() Rejected → .catch() Remember: 🤝 Promise = A future result ✅ .then() = Success ❌ .catch() = Error 🔚 .finally() = Always executes 🚀 Promises make asynchronous code cleaner and easier to maintain than callbacks.