Today I learned one of the most important concepts in JavaScript—asynchronous programming with Promises. Initially, Promises seemed confusing, but after understanding how they work internally, the concept became much clearer.
1. What is Callback Hell?
A callback is a function passed to another function that executes after an asynchronous operation completes.
When multiple asynchronous operations depend on each other, callbacks become deeply nested.
getUser(userId,function(user){getOrders(user.id,function(orders){getOrderDetails(orders[0].id,function(details){processOrder(details,function(result){console.log(result);});});});});This deeply nested structure is called Callback Hell or the Pyramid of Doom.
Problems with Callback Hell
- Difficult to read
- Hard to debug
- Difficult to maintain
- Error handling becomes complicated
To solve these problems, JavaScript introduced Promises.
2. What is a Promise?
A Promise is an object that represents the eventual result of an asynchronous operation.
It promises that it will either:
- Complete successfully
- Fail with an error
A Promise starts in the Pending state and eventually becomes either Fulfilled or Rejected.
3. Promise States
Every Promise has three possible states.
Pending
The asynchronous operation is still running.
Fulfilled
The operation completed successfully.
Rejected
The operation failed.
A Promise can change its state only once.
Pending
|
| resolve()
▼
Fulfilled
OR
Pending
|
| reject()
▼
Rejected
4. Creating a Promise
A Promise is created using the Promise constructor.
constpromise=newPromise((resolve,reject)=>{});One important thing I learned today is that I do not create resolve and reject myself.
JavaScript automatically provides these two functions to the Promise executor.
Conceptually, it works like this:
newPromise((resolve,reject)=>{});Here,
resolve()is used when the operation succeeds.reject()is used when the operation fails.
5. Using resolve() and reject()
Example:
constpromise=newPromise((resolve,reject)=>{constmarks=80;if (marks>=35)resolve("Pass");elsereject("Fail");});If the condition is true, the Promise becomes Fulfilled.
Otherwise, it becomes Rejected.
6. Handling Promises
then()
.then() executes only when the Promise is fulfilled.
promise.then(result=>{console.log(result);});catch()
.catch() executes only when the Promise is rejected.
promise.catch(error=>{console.log(error);});finally()
.finally() executes whether the Promise succeeds or fails.
It is useful for cleanup operations like hiding loading indicators or closing connections.
promise.finally(()=>{console.log("Finished");});7. Promise Chaining
Every .then(), .catch(), and .finally() returns another Promise.
This allows us to chain multiple asynchronous operations.
Promise.resolve(10).then(value=>value*2).then(value=>value+5).then(value=>console.log(value));Output:
25
Each .then() receives the value returned by the previous .then().
8. Error Propagation
One of the most interesting concepts I learned today is Error Propagation.
If an error occurs inside any .then() callback, JavaScript automatically skips all remaining .then() callbacks and jumps directly to the nearest .catch().
Promise.resolve(10).then(value=>{thrownewError("Something went wrong");}).then(()=>{console.log("This will never execute");}).catch(error=>{console.log(error.message);});Output:
Something went wrong
This makes error handling much simpler because a single .catch() can handle errors from multiple Promise operations.
9. Practical Promise Example
functionlogin(username,password){returnnewPromise((resolve,reject)=>{setTimeout(()=>{if (username==="harshith"&&password==="1234"){resolve("Login Successful");}else{reject("Invalid Username or Password");}},2000);});}login("harshith","1234").then(message=>console.log(message)).catch(error=>console.log(error));This example helped me understand when to call resolve() and reject() based on a condition.
10. Key Takeaways
- Callback Hell makes asynchronous code difficult to read and maintain.
- Promises solve Callback Hell by making asynchronous code cleaner.
- Every Promise has three states: Pending, Fulfilled, and Rejected.
- JavaScript automatically provides the
resolve()andreject()functions when creating a Promise. resolve()changes a Promise to Fulfilled.reject()changes a Promise to Rejected..then()handles successful results..catch()handles errors and rejected Promises..finally()executes regardless of success or failure.- Promise chaining makes complex asynchronous operations easier to manage.
- Errors automatically propagate through the Promise chain until they are handled by the nearest
.catch().
Conclusion
Today's learning helped me understand how JavaScript manages asynchronous operations using Promises.I learned why callback hell occurs, how Promises improve code readability, how Promise states work, how resolve() and reject() are provided by JavaScript, and how .then(), .catch(), .finally(), Promise chaining, and error propagation make asynchronous programming much cleaner and easier to maintain.
Understanding these concepts has also given me a much stronger foundation for learning async/await, since it is built on top of Promises.


Top comments (0)