DEV Community

markzzw
markzzw

Posted on

Advance JavaScript - Promise

This article primarily covers some common functions and usage techniques related to Promises, aiming to assist readers in utilizing Promises more easily to solve problems.

Basic

Promise

A Promise is a JavaScript object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. It is commonly used for handling asynchronous operations such as network requests, file operations, and database queries.

A Promise can be in one of three states:

Pending: The initial state. The Promise is neither fulfilled nor rejected.

  1. Fulfilled: The Promise has been successfully resolved with a value. This state is also referred to as "resolved".
  2. Rejected: The Promise encountered an error or failure during the asynchronous operation.

new Promise() returns a Promise object, this object can handle the result of the async.

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* success */){
    resolve(value);
  } else {
    reject(error);
  }
});

// Ajax
const getJSON = function(url) {
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();
  });

  return promise;
};
Enter fullscreen mode Exit fullscreen mode

Promise.then(successFn, failFn);

When we need to handle the result of an asynchronous operation, we use the then method after a Promise object to process the result. The then method takes two parameters: the first one is the success callback function that receives the value resolved by resolve, and the second one is the error callback function that receives the value rejected by reject.

getJSON("/posts.json").then(function(json) {
  console.log('result: ' + json);
}, function(error) {
  console.error(error);
});
Enter fullscreen mode Exit fullscreen mode

The first successFn of the then function can return a value, which can then be accessed by the successFn of the next then function, forming a chain of calls.

// You can use chaining to perform multiple asynchronous operations in sequence.
getJSON("/post/1.json").then(function(post) {
  setPost(post.article);
  return getJSON(post.commentURL);
}).then(function (comments) {
  setComments(comments);
}, function (err){
  console.log("rejected: ", err);
});
Enter fullscreen mode Exit fullscreen mode

Promise.catch(failFn);

As shorthand of the then(null | undefined, failFn), You can place an error handler at the end to listen for errors from the previous then statements.

const promise = new Promise((resolve, reject) => {
  resolve('resolve');
});

promise.then(res => {
  console.log(res);
  throw 'error msg';
}).catch(err => {
  console.log(err)
})

// "resolve"
// "error msg"
Enter fullscreen mode Exit fullscreen mode

Once an error occurs, the execution of statements after the error will be stopped.

const promise = new Promise((resolve, reject) => {
  resolve('resolve');
});

promise.then(res => {
  throw 'error msg';
  console.log(res);
}).catch(err => {
  console.log(err)
})

// "error msg"

const promise = new Promise((resolve, reject) => {
  reject('rejected');
});

promise.then(res => {
  throw 'error msg';
  console.log(res);
}).catch(err => {
  console.log(err)
})

// "rejected"
Enter fullscreen mode Exit fullscreen mode

If a resolve operation is performed before a reject operation, the reject operation will not be executed. Conversely, if a reject operation is performed before a resolve operation, the resolve operation will not be executed. This follows the principle of Promises that once a state transition occurs, it cannot be changed again.

image.png

image.png

If an error occurs outside the current event loop, it cannot be caught.

const promise = new Promise((resolve, reject) => {
  resolve('resolved')
  setTimeout(function () { throw 'error test' }, 0);
});

promise.then(res => {
  console.log(res);
}).catch(err => {
  console.log('err',err)
})
Enter fullscreen mode Exit fullscreen mode

image.png

Because catch is a shorthand for then, you can chain then after the catch. However, if there is a catch method followed by a then method, any error that occurs before the subsequent catch method will not be caught.

promise.catch(function(error) {
  console.log('oh no', error);
})
.then(function() {
  console.log('carry on');
});
// carry on
Enter fullscreen mode Exit fullscreen mode

Promise.finally(onFinally);

The finally() method of a Promise instance is used to register a function that will be called when the promise is settled (either resolved or rejected). It immediately returns an equivalent Promise object, which allows you to chain other Promise methods. However, when chaining other methods, the finally() method will always return the previous result.

image.png

Senior

Promise.all(promiseArr)

The static method Promise.all() takes an iterable of Promises as input and returns a Promise. When all the input Promises are fulfilled, the returned Promise is also fulfilled (even if the iterable is empty) and resolves to an array containing all the fulfilled values. If any of the input Promises are rejected, the returned Promise is rejected with the reason of the first rejection.

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(values);
});
// [3, 42, "foo"]

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

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values);
}).catch(error => {
  console.log('error', error)
});
// "error" 3
// then does not react, catch will get the first reject value.
Enter fullscreen mode Exit fullscreen mode

If we attach a catch function to each Promise instance, we can retrieve the corresponding catch value inside Promise.all(). If the catch function does not return any value, the corresponding item in the values array within the then method of Promise.all() will be undefined.

image.png

Promise.allSettled(promiseArr)

This function addresses the issue of Promise.all terminating when encountering a rejection. It will execute all the promises and then retrieve the results in the then method. It's important to note that the structure of the resolved object and the rejected object may differ slightly.

image.png

Promise.any(promiseArr)

The static method Promise.any() takes an iterable of Promises as input and returns a Promise. When any of the input Promises is fulfilled, the returned Promise is fulfilled and returns the first fulfilled value. If all the input Promises are rejected (including when an empty iterable is passed), it will be rejected with an array of rejection reasons AggregateError

image.png

image.png

Promise.race(promiseArr)

The static method Promise.race() takes an iterable of Promises as input and returns a Promise. The returned Promise will be settled (either fulfilled or rejected) as soon as the first Promise in the iterable is settled.

image.png

MDN

Top comments (0)