What are Promises in JavaScript?
Promises are objects in Javacript that are used to indicate success or failure in asycnhronous operations.
JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat.
Brief Introduction
A promise is an object that signals completion or failure of an asynchronous task and its result. It means using promises we can ensure that our task will get completed or failed in some time in future, so that we don’t have to wait for its completion to execute next task.
Need for promises
Javascript executes everything line by line. But when we want to execute a slow process like fetching a file from a server we cannot do it traditionally since it will block our browser and severely affect the performance of our application.
Callbacks were introduced to solve this problem, wherein you pass a function inside another function and the former is called when the latter has finished its execution. But soon with a lot of callbacks passing inside one another, readability became a problem, popularly known as callback hell.
//Code Snippet#1
async1((err, res) => {
if (!err) async2(res, (err, res) => {
if (!err) async3(res, (err, res) => {
console.log('async1, async2, async3 complete.');
});
});
});
ES6 introduced Promises to resolve this problem. They use callbacks under the hood. But Promises provide a clearer syntax that chains asynchronous commands so they run in series.
Creating & invoking a promise with an example
Let’s create a shoe store.
//Code Snippet#2
let store = [‘Adidas’, ‘Reebok’, ‘Puma’, ‘Skechers’];
Let’s create a promise to check the brand of the shoes.
//Code Snippet#3
const checkBrand = new Promise ((resolve,reject)=>{
setTimeout(()=>{
let check = store.includes("Reebok");
if(check)
resolve('My fav shoe brand is there!')
else
reject("Let's go somewhere else :(")
},3000)
})
Now invoke the promise
//Code Snippet#4
checkBrand
.then(data=>console.log(data))
.catch(err=>console.log(err))
//My fav shoe brand is there!
Code flow explained
The promise can be created in below fashion-
//Code Snippet#5
const myFirstPromise = new Promise((resolveFunc, rejectFunc) => {
// do something asynchronous which eventually calls either:
//
// resolveFunc(someValue) // fulfilled
// or
// rejectFunc("failure reason") // rejected
});
A Promise object is created using the new keyword and its constructor. This constructor takes a function, called the “executor function”, as its parameter.
This function should take two functions as parameters. The first of these functions (resolve) is called when the asynchronous task completes successfully and returns the results of the task as a value. The second (reject) is called when the task fails, and returns the reason for failure, which is typically an error object. Both resolve and reject functions are provided by the constructor at the time of promise creation.
Some useful methods of Promises
- Promise.all() — When you go to a shoe store you tell the sales person your requirements and if he promises all your requirements being fulfilled then you buy the shoe.
//Code Snippet#6
const checkColor = Promise.resolve(“Blue”);
const checkDiscount = '10%';
//checkBrand = ‘Reebok’ (defined in Code Snippet#3)
Promise.all([checkColor, checkDiscount, checkBrand]).then((values) => {
console.log(values);
});
//[ 'Blue', '10%', 'My fav shoe brand is there' ]
It takes an array of promises and returns array of resolved values or if any one of them fails then it returns the rejected value irrespective of whether others were resolved or not.
2. Promise.any() — Suppose you and your friend go to two different stores looking for same shoe specification, i.e. Blue colored Reebok shoes with 10% discount and whoever finds it first buys the shoe.
//Code Snippet#7
const checkStore1 = new Promise((resolve) => setTimeout(resolve, 100, 'store1'));
const checkStore2 = new Promise((resolve) => setTimeout(resolve, 500, 'store2'));
const promises = [checkStore1, checkStore2];
Promise.any(promises).then((value) => console.log(value));
It takes an array of promises and as soon as any one promise is resolved it returns the resolved value or if all of the promises failed to resolve then it returns aggregated error.
3. Promise.race() —Suppose you’re designing your shoe website and you make api calls to fetch shoes. The api call should fail if it takes longer than 5 sec.
//Code Snippet#8
const data = Promise.race([
fetch("/api"),
new Promise((resolve, reject) => {
// Reject after 5 seconds
setTimeout(() => reject(new Error("Request timed out")), 5000);
}),
])
.then((res) => res.json())
.catch((err) => displayError(err));
It takes input as an array of promises and as soon as any one promise fulfils or rejects, it returns with fulfilled or rejected value.
Conclusion
We have seen now what are promises, why do we need them, what is callback hell. How to create and apply Promises in our code. Similar to these are async/await. They are syntactical sugar over promises but it saves us from writing .then() chains which becomes unreadable with too many promises pieced together.