MSDN Tutorials

Understanding JavaScript Promises

Promises are a powerful feature in JavaScript that allow you to handle asynchronous operations more effectively. They represent the eventual result of an asynchronous operation, whether it's a success or a failure.

What is a Promise?

A Promise is an object that may produce a single value, either a resolution value, or a reason that the promise was rejected. It is used in asynchronous computations. A Promise object is created using the Promise constructor, which takes a function (called the "executor") as an argument. The executor function itself receives two arguments: resolve and reject. These are functions provided by the JavaScript engine.

Creating a Simple Promise


const myPromise = new Promise((resolve, reject) => {
  // Simulate an asynchronous operation, like fetching data
  setTimeout(() => {
    const success = true; // or false to simulate failure

    if (success) {
      resolve("Data fetched successfully!"); // Resolve with a value
    } else {
      reject("Error fetching data."); // Reject with an error reason
    }
  }, 2000); // Simulate a 2-second delay
});
            

Consuming Promises: .then() and .catch()

Once a promise is created, you can consume its result using the .then() and .catch() methods.

Handling Promise Results


myPromise
  .then((result) => {
    console.log("Success:", result); // This will log "Success: Data fetched successfully!"
  })
  .catch((error) => {
    console.error("Failure:", error); // This will log "Failure: Error fetching data." if success is false
  });
            

Promise States

A Promise can be in one of three states:

Once a promise is settled (either fulfilled or rejected), its state cannot change.

.finally()

The .finally() method is used to execute a piece of code regardless of whether the promise was fulfilled or rejected. This is useful for cleanup operations.

Using .finally()


myPromise
  .then((result) => {
    console.log("Success:", result);
  })
  .catch((error) => {
    console.error("Failure:", error);
  })
  .finally(() => {
    console.log("Promise settled (either fulfilled or rejected).");
    // Example: hide a loading spinner
  });
            

Chaining Promises

Promises can be chained together, allowing for sequential execution of asynchronous operations. Each .then() method can return another promise, or a value. If a .then() returns a promise, the next .then() will wait for that promise to settle.

Chaining for Sequential Operations


function step1() {
  return new Promise(resolve => setTimeout(() => { console.log("Step 1 complete"); resolve(10); }, 1000));
}

function step2(value) {
  return new Promise(resolve => setTimeout(() => { console.log(`Step 2 complete with value ${value}`); resolve(value * 2); }, 1000));
}

function step3(value) {
  return new Promise(resolve => setTimeout(() => { console.log(`Step 3 complete with value ${value}`); resolve(value + 5); }, 1000));
}

step1()
  .then(step2)
  .then(step3)
  .then((finalResult) => {
    console.log("Final result:", finalResult); // Expected: (10 * 2) + 5 = 25
  })
  .catch(error => {
    console.error("An error occurred:", error);
  });
            

Advanced Promise Handling: Promise.all() and Promise.race()

JavaScript provides static methods on the Promise object for more complex scenarios:

Promise.all() Example


const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log("All promises resolved:", values); // [3, 42, 'foo']
}).catch(error => {
  console.error("One of the promises rejected:", error);
});
            

Promise.race() Example


const p1 = new Promise((resolve, reject) => { setTimeout(resolve, 500, 'one'); });
const p2 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'two'); });

Promise.race([p1, p2]).then((value) => {
  console.log("First promise to settle:", value); // 'two'
}).catch(error => {
  console.error("First promise to settle rejected:", error);
});
            

Conclusion

JavaScript Promises provide a clean and efficient way to manage asynchronous code, making your applications more responsive and easier to maintain. By understanding states, .then(), .catch(), .finally(), and static methods like Promise.all() and Promise.race(), you can harness the full power of asynchronous programming in JavaScript.