Promises in JavaScript

Learn via video course
FREE
View all courses
JavaScript Course With Certification: Unlocking the Power of JavaScript
JavaScript Course With Certification: Unlocking the Power of JavaScript
by Mrinal Bhattacharya
1000
4.8
Start Learning
JavaScript Course With Certification: Unlocking the Power of JavaScript
JavaScript Course With Certification: Unlocking the Power of JavaScript
by Mrinal Bhattacharya
1000
4.8
Start Learning
Topics Covered

To grasp what is promise in JavaScript, it's crucial to recognize the challenge they address. JavaScript, being single-threaded, executes tasks sequentially. To avoid blocking for long time processes, asynchronous tasks are essential. Promises manage these tasks, allowing concurrent execution and notifying upon completion.

Async functions inherently return promises, simplifying asynchronous operation management. Promises effectively handle multiple asynchronous tasks, preventing callback hell and promoting code manageability over traditional callback-based approaches.

What is a Promise in JavaScript

JavaScript Promise Syntax

The Promise syntax involves creating a new promise object with a callback function. This callback function accepts two parameters: resolve and reject.

Inside the callback, the operations are performed if they are executed successfully, then the resolve is called else reject if failure occurs.

Promises in javascript have four states: fulfilled for success, rejected for failure, pending while unresolved, and settled once either fulfilled or rejected.

Description of Promises in JavaScript

Callback and promise in javascript are both used to handle asynchronous code in JavaScript. When you use callbacks, you send callback functions as parameters to another function. Using promises, you do not need to PASS callback functions. But instead, ATTACH them with the promise using the .then() method.

JavaScript Promises States

JavaScript Promises have four states:

Pending

This is the initial state when a promise is created, and it's neither fulfilled nor rejected. It's like waiting for an outcome.

Fulfilled

The promise successfully completed its operation, and the associated value is available. This is often referred to as "resolved" as well.

Rejected

The promise operation failed, and an error reason is provided. This indicates that the promise couldn't deliver what was expected.

Settled

A settled Promise indicates fulfilment or rejection of an asynchronous task. It signifies completion, whether successful or unsuccessful, simplifying asynchronous code management.

Chained Promises in JavaScript

Promise methods like .then(), .catch(), and .finally() enable actions upon settled promises, supporting chaining due to their return of promise objects.

.then() accepts callbacks for fulfilment and rejection, generating new promises for chaining. For instance:

A chain proceeds to the following link even without a callback in a .then(). Thus, it's safe to skip rejection handlers until the final .catch(). This approach ensures smooth processing and simplifies error handling in promise chains.

Handling rejected promises in each .then() is crucial for immediate error resolution, ensuring error propagation down the chain; however, in scenarios where immediate handling isn't necessary, deferring error management until a final .catch() statement simplifies code. Essentially, a .catch() serves as a .then() without a fulfilment callback, exclusively for handling promise rejections.

The finally() method of Promise instances sets a function to execute when the promise is resolved, regardless of its outcome. It promptly returns a new Promise object, facilitating further method chaining.

Thenables

Thenable promises in JavaScript have a "then()" method, allowing them to be treated similarly to standard promises. They are commonly used as a bridge between third-party libraries, legacy code, and native promises. Thenable promises can be used instead of regular promises by implementing the "then()" method and returning a new promise. This enables interoperability between different promise implementations and ensures consistent behaviour. It allows developers to work with promises from various sources without modifying existing code. Example

Promise concurrency

The Promise class offers four static methods for managing asynchronous tasks concurrently:

Promise.all()

Resolves when all promises are fulfilled, rejects if any promise is rejected.

Promise.allSettled()

Resolves when all promises settle (fulfilled or rejected).

Promise.any()

Resolves when any promise is fulfilled, rejects if all promises are rejected.

Promise.race()

Settles when any promise settles (fulfil or reject).

These methods accept an iterable of promises and return a new promise. They support subclassing, requiring the subclass to implement the same constructor signature and a resolve static method. JavaScript's single-threaded nature means only one task executes at a time, although promises can appear to execute concurrently. True parallelism in JavaScript requires worker threads.

Constructor

  • Create your own promise using the Promise() constructor.
  • Pass the executor function as the parameter to the constructor.
  • The executor function gets executed whenever the promise is created.

We have a promise() constructor in JavaScript. This is used to wrap those functions which do not support promises by default.

Syntax

Executor Function is passed as a parameter to the Promise constructor. It is executed by the constructor function whenever a new promise is created using the constructor.

We can create promises in javascript using the Promise constructor in the following way:

Instance methods

  • Promise.prototype.then() handles the value for the promise in case it is fulfilled successfully.
  • Promise.prototype.catch() handles the promise in case an error occurs or the promise gets rejected.
  • Promise.prototype.finally() runs a piece of code as soon as the promise settles, regardless of the promise's status - fulfilled or rejected.
  • Promise.prototype.then() This method takes in two parameters - callback functions for success and failure (both optional) and returns a promise.

Syntax: p.then(onFulfilled[, onRejected]); Parameters

  1. onFulfilled This function is called if the promise is fulfilled.
  2. onRejected This function is called if the promise is rejected.

Example:

  • Promise.Prototype.catch() This method handles errors for the promise. If an error occurs, the catch method executes the error handler function passed as a parameter to the catch method.

Syntax: p.catch(onRejected); Parameter: onRejected is the function to be called when an error occurs or the promise gets rejected.

Example:

Both of them are internally the same. The catch() method internally uses then(onFulfilled, onRejected) to handle the rejected promise! So, a promise can be set to handle errors/rejections both ways.

  • Promise.Prototype.finally() This method returns a new promise when it finally goes to the settled state, i.e., it gets fulfilled or rejected. This is a handy method when we want to run a piece of code when the promise settles, whether it gets rejected or fulfilled.

Syntax: p.finally(onFinally); Parameter: onFinally is the function that is executed when the promise either fulfils or gets rejected.

Example:

Examples

Basic Example

Look at a few examples to understand promises in detail:

Output:

output of the example1

Explanation: A promise is created using the Promise() constructor in the code above. This promise will be resolved or rejected based on the value of the count variable.

Example with diverse situations

In the above example, When consoling out promiseCount, we get a promise as the output. But how do we extract the response received? And what about the case our promise is rejected because of the negative value of the count variable?

  • We can use .then() to extract the value of the fulfilled promise and .catch() to extract the reason for rejection (in case it gets rejected) in the following way:

Output:

output of example1

Advanced Example

Now, let us look at a more realistic example. In every web application, we need to send requests to the server for data to be displayed to the view (on the browser).

This request takes some to come back with the requested data. At times, the request might encounter an error while processing. But our web app must act quickly. Hence, we use promises to handle this task.

We'll use the fetch() method to make a request to the server and get a random fact about cats. fetch() returns a promise, so we can chain this to get the response out:

Output:

output of example2

Browser compatibility

Below is the table of browser compatibility for promises in JavaScript for almost all the browsers we use today.

Browser Compatibilities

Conclusion

  • JavaScript can only perform one task at a time and cannot wait for long tasks to complete, requiring asynchronous handling for such tasks.
  • To handle asynchronous tasks effectively, we learnt what is promise in javascript.
  • Promises are precisely what you would expect from its name. They promise that a response will be sent to the browser. Meanwhile, other tasks can be performed.
  • Promises can have four states - PENDING, FULFILLED, REJECTED, and SETTLED.
  • A promise begins in the Pending state and can transition to fulfilled or rejected upon completion of its asynchronous task.