How to Resolve Callback Hells with Lovely JavaScript Promises
Make your promise…

In my last article, we have seen how JavaScript with Node.js performs asynchronous operations. Do you remember callbacks?
Callback is the backbone for asynchronous programming in Javascript. There are two main problems we face in using callbacks in our programming:
1. Callback hell
There are instances when we make a callback inside of a callback (called nested callbacks). It causes issues in code readability and understanding.
2. Difficulty in handling errors
When an asynchronous function or an asynchronously invoked callback throws an exception, there is no way for that exception to propagate back to the initiator of the asynchronous operation. It breaks the exception handling.
So, the simplest solution is using our lovely Promises.
A Promise is an object built on callbacks, which represents the result of an asynchronous computation. The result may or may not be ready. Promise works asynchronously only. There is no way of getting the value through synchronous calls. You can only ask the Promise to call a callback function when the value is ready.
Promises provide solutions for nested callbacks through re-expressing the nested callbacks in the form of a Promise chain. And through Promise, we can handle the errors in the proper way by handling them in the Promise chain.
A promise can be “kept” or “broken”.
Using the same logic, in JavaScript a Promise can be “fulfilled” or “rejected”.
There is another state there as well, that is “pending”. When a Promise is in a state where it’s neither been fulfilled nor rejected, it is pending. A Promise is settled once it is fulfilled or rejected.
A Promise has a single argument, that is a function of two parameters: resolve and reject. If a Promise is fulfilled or resolved, the result of the async code for which we promised will be the value in the resolve parameter. Else, if it gets rejected, the Error object will be the value in the reject parameter. When a Promise is returned, either resolve or reject will have the value and the other will be undefined.
The Promise object has instance methods. We frequently use then() and catch().
How to create a Promise?
Through the Promise constructor, we can create a Promise.


Here, in the first picture, I take a simple function and let you understand how a functional requirement is done by callback and Promise.
In the second picture, we can see that addPositive() is returning a Promise instead of accepting a callback argument.
After two seconds, this function will return a Promise object. Instead of passing the callback function straight away to addPositive(), we pass it to the then() as the first argument. So, the return value will be passed to the callback function which we passed in then().
If an error occurs, that will be passed to the callback that is passed in catch(). Or the error can also be passed to the callback function which we pass as a second argument in then(). This will be called when the Promise gets rejected. In common, we use the catch() method invocation rather than passing two callbacks to the then() method.
Chaining Promises
Promises can be chained. How?.
We can express a sequence of asynchronous operations as a linear chain of then() invocation. This is the solution for the above-mentioned callback hell.

In the Promise chain, as I said, more than one method invocation can be seen and they are being called sequentially.
- The addPositive() function returns a Promise1 Object.
- After that, we invoke the then() method of the Promise1 and pass the ‘result’ callback function, which will be called when the Promise1 is fulfilled.
- The then() method stores our ‘result’ callback somewhere and returns a new Promise2.
- After that, the next task will begin when the ‘result’ callback is invoked(means Promise1 is fulfilled now) and we invoke the then() method of Promise2 and pass the ‘result2’ callback which will be invoked when Promise2 get fulfilled and no more calling of further promises at this point.
- So now, our Promise settles and our computation ends.
In ES2018, the Promise object also defines a .finally() method which is the functional equivalent to the finally clause in exception handling mechanism.
Some more information regarding Promises
Promise.all()
We can run more than one Promise in parallel. Promise.all() function does this. It takes an array of Promise objects as input and returns a Promise. The returned Promise will be rejected if any of the input Promises get rejected. Else, it will be fulfilled with an array of fulfilled values of each input Promises.
Promise.allSettled()
This function takes an array of Promises as input and returns a Promise as the Promise.all() function does. But there are major differences:
- This function will never reject the returned Promise.
- This does not fulfil the returned Promise until all the input Promises have settled.
The Promise resolves to an array of objects, where each object is a result (the result may be of fulfillment value if input Promise gets resolved, else an error or rejection value if the input Promise gets rejected) of each input Promise.
Promise.race()
If we want to run a number of Promises, but we only care about the result of the first Promise, then we can go for this function. This returns a Promise that is fulfilled or rejected when the first of the Promises in the input array is fulfilled or rejected.
I hope you now have a better understanding of how Promises work in JavaScript.
See you in my next article!
More content at plainenglish.io