• Home
  • About
    • i m h o . j photo

      i m h o . j

      baby web developer's blog

    • Learn More
    • Email
    • LinkedIn
    • Github
    • SoundCloud
  • Posts
    • All Posts
    • All Tags
    • All Categories
  • Projects

I promise, you will understand Promise after reading this (Part II)

04 Aug 2019

Reading time ~4 minutes

How can I use Promise?

In Promise Part I, I gave a general overview on why Promise would be such a lifesaver when dealing with async operations in JavaScript.

Now let’s look into how we can go about utilizing this amazing feature.

Constructing a Promise Instance

Promise turns an async operation into an instance through Promise constructor.

Promise constructor takes a callback function as an argument, and that callback function takes in two functions called resolve and reject.

var promiseInstance = new Promise(function (resolve, reject) {
  
  // async operation here
  
  if (/* async operation succeeds */) {
    resolve(/* result */);
  } else { /* async operation fails */
    reject(/* failure reason */);
  }
});

The callback function passed in as an argument in Promise constructor does async operations inside, and invokes resolve with the result of async operation passed in as its argument if the operation was successful. reject, on the other hand, is invoked with the failure reason when the operation fails.

Let’s fill in some blanks and make the above code look more legitimate.

(below example is from poiemaweb)

const promiseAjax = (method, url, payload) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(method, url); // method: kind of task, url: place where I can find this info
    xhr.setRequestHeader('Content-type', 'application/json'); 
    xhr.send(JSON.stringify(payload));

    xhr.onreadystatechange = function () {
      // if fetch operation is not complete, ignore.
      if (xhr.readyState !== XMLHttpRequest.DONE) return;

      if (xhr.status >= 200 && xhr.status < 400) {
        // call resolve method to pass the result
        resolve(xhr.response); // Success!
      } else {
        // call reject method to pass the error message
        reject(new Error(xhr.status)); // Failed...
      }
    };
  });
};

promiseAjax('GET', 'http://jsonplaceholder.typicode.com/posts/1')

promiseAjax stores a function that returns a new Promise instance.

The result of the async operation is passed into resolve method if the operation is successfully carried out. If the operation fails, the error message is passed into reject method.

We must be able choose what to do with result or the error message, and this is where .then and .catch method come into play.

Handling result and error of a Promise instance

.then

The above async function passes the result into resolve method. This means that promiseAjax('GET', 'http://jsonplaceholder.typicode.com/posts/1') this line of code is referencing to a newly created Promise instance that is passing the result via resolve method.

The result can be handled by chaining .then method to the Promise instance.

then method takes up to two arguments, which are both callback functions. The first callback is invoked when resolve is invoked in the Promise instance, and the second callback is invoked when reject is invoked in the Promise instance.

then method by default returns a Promise instance.

Depending on the return value of the callback/handler, the Promise returned by then either resolves or rejects with the returned value. There are several cases regarding this. Check MDN .then for the list of behaviors.

promiseAjax('GET', 'http://jsonplaceholder.typicode.com/posts/1')
      .then(function (result) {
  	      		return JSON.parse(result);
      			}, 
            function (errorMessage) {
  						 return console.error(errorMessage);
						});

The first callback in then receives result that was passed from the Promise instance from promiseAjax. The callback then returns JSON.parse(result). Promise instance returned by then gets resolved with this return value of the callback!

This can be quite a lot to take in so let’s divide and conquer.

  1. .then method returns a Promise instance
  2. A Promise instance should resolve or reject depending on the outcome of the task.
  3. If the callback returns a value, the above Promise instance created by then method resolves with that returned value of the callback. (There are also cases where the callback returns nothing, or throws an error, etc.)

Interesting right?

What if the Promise instance that then is being invoked has already been rejected?

No worries! According to MDN, if a handler function returns an already rejected promise, the promise returned by then gets rejected with that promise’s value as its value.

There’s a whole list on what happens to the Promise instance returned by then when either the callback is called, so make sure to check it for yourself.

.catch

We have already seen that then ‘s second argument, a callback that is invoked when Promise instance invokes reject, "catches" error. However, this callback will only “catch” the errors that occur in async operations (a.k.a. when reject is invoked). However, it is possible that errors occur inside then methods as well (when Promise instance created by then doesn’t invoke reject). And that’s when catch can become handy.

promiseAjax('GET', 'http://jsonplaceholder.typicode.com/posts/1')
  .then(JSON.parse)
  .then(render)
  .catch(console.error);

(code example from poiemaweb)

Other Promise methods

Promise.resolve & Promise.reject

Promise.resolve and Promise.reject turns a value into a Promise instance.

const resolvedPromise = Promise.resolve([1, 2, 3]);
resolvedPromise.then(console.log); // [ 1, 2, 3 ]

//above is same as below

const resolvedPromise = new Promise(resolve => resolve([1, 2, 3]));
resolvedPromise.then(console.log); // [ 1, 2, 3 ]
const rejectedPromise = Promise.reject(new Error('Error!'));
rejectedPromise.catch(console.log); // Error: Error!

//above is same as below

const rejectedPromise = new Promise((resolve, reject) => reject(new Error('Error!')));
rejectedPromise.catch(console.log); // Error: Error!

(code example from poiemaweb)

There’s also Promise.all and Promise.race, but I will not go into detail on what these methods do.

These are also very interesting methods in Promise, so check them out for yourself!

You can begin here: MDN Promise.all, MDN Promise.race.



javascriptPromisegrammarasyncES6callback Share Tweet +1