Promises are a powerful tool for dealing with asynchronous code in JavaScript, allowing you to avoid the callback hell. In this blog post, we will explore how to use promises, including creating promises, consuming promises, chaining promises, handling errors, and orchestrating promises.
Introduction to Promises
A promise is a proxy for a value that will eventually become available. It provides a way to work with asynchronous code without writing too many callbacks. Promises were standardized and introduced in ES2015, and now they have been superseded in ES2017 by async functions.
How Promises Work, in Brief
Once a promise is called, it starts in a pending state. While the promise does its own processing, the caller function continues its execution, waiting for the promise to either return in a resolved state or a rejected state. This allows the function to continue its execution without blocking.
Which JS API Use Promises?
Promises are widely used in modern JavaScript in addition to your own code and library code. They are used by standard Web APIs such as the Battery API, Fetch API, and Service Workers. It is unlikely that you will find yourself not using promises in modern JavaScript.
Creating a Promise
To create a promise, use the Promise constructor provided by the Promise API. Initialize it using new Promise()
and pass a callback function with two parameters, resolve
and reject
. Inside the callback function, you can check certain conditions and call resolve
or reject
accordingly.
Consuming a Promise
To consume or use a promise, you need to call methods like then
and catch
on the promise instance. The then
method is used to handle the resolved state of the promise and the catch
method is used to handle the rejected state. These methods take callback functions as parameters.
Chaining Promises
Promises can be chained together by returning a promise from within another promise’s then
callback. This creates a chain of promises, allowing you to execute a sequence of asynchronous operations. A great example of chaining promises is the Fetch API, which allows you to get a resource and queue a chain of promises to execute when the resource is fetched.
Handling Errors
When an error occurs in a promise or in any chained promises, the control goes to the nearest catch
statement in the promise chain. You can use the catch
method to handle errors and perform error handling logic. If an error is thrown inside a catch
block, you can chain another catch
to handle it, and so on.
Orchestrating Promises
Promise.all()
If you need to synchronize different promises and execute something when they are all resolved, you can use the Promise.all()
method. It takes an array of promises as input and returns a new promise that resolves when all the promises in the array have been resolved. You can then use then
to handle the resolved results or catch
to handle any errors.
Promise.race()
Promise.race()
runs as soon as one of the promises you pass to it resolves, and it runs the attached callback once with the result of the first resolved promise. This can be useful when you only care about the result of the first promise that resolves. You can use then
to handle the result or catch
to handle any errors.
Common Errors
Uncaught TypeError: undefined is not a promise
If you encounter the Uncaught TypeError: undefined is not a promise
error, make sure you use new Promise()
instead of just Promise()
. This error occurs when using Promise()
without the new
keyword to create a new promise instance.