[JavaScript – ES2015] Promises

Asynchronous processes become more and more essential in modern JavaScript development because the front end side generally communicate with the back end with Ajax API calls. You might be familiar with jQuery deferred pattern. Now JavaScript itself provides the Promises.

 

1. Promises

A promise is an object that listens to the async operation and returns the result when the operation is completed.

A Promise can be in one of the following 3 states:

  • Pending
  • Fulfilled
  • Rejected

 

2. Resolve

In ES2015, a promise is an object. You can create an instance with 2 parameters: “resolve” and “reject“. They are functions to be called.

When the async operation completes successfully, you need to call the “resolve(result)” function with data in a Promise.

To use a promise, create a Promise object and call the “then()” method with a handler.

let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    let result = { value: 10 };
    resolve(result);
  }, 1000); // 1 sec
});

console.log("Before");
promise.then((data) => {
  console.log(`Done: ${data.value}`)
});
console.log("After");

In the Console screen, you can see

Before
After
Done: 10

This show how the Promise works in a simplest manner.

 

3. Reject

What if when something goes wrong during the async operation?

In the promise, the “reject()” function needs to called. In the calling code, you can provide the error handler as the second argument of the “then()” function.

let promise = new Promise((resolve, reject) => {
  reject(Error('failed'));
});

promise.then(() => {
  console.log('Success');
}, (error) => {
  console.log(error.message);
});

Another way to handle the error is to use the “Promise.catch()” method.

let promise = new Promise((resolve, reject) => {
  reject(Error('failed'));
});

promise.then(() => {
  console.log('Success');
}).catch(error => {
  console.log(error.message);
});

 

4. Promise Chaining

You can return another promise inside the promise handler. In so doing, async actions will be executed in a sequential way.

let task1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Doing the task 1")
      resolve({ value: 10 });
    }, 1000); // 1 sec
  })
};

let task2 = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("Doing the task 2")
      resolve({ value: 10 + value });
    }, 1000); // 1 sec
  })
};

task1().then(data => {
  console.log(`task 1 value: ${data.value}`);
  return task2(data.value);
}).then(data => {
  console.log(`task 2 value: ${data.value}`);
});

The result is like this:

Doing the task 1
task 1 value: 10
Doing the task 2
task 2 value: 20

This is a really useful pattern.

 

5. Parallel Processing

Rather than sequential chaining, you might want to do multiple tasks in parallel.

Suppose you want to do some complex math calculations many times. You can make a list of promises and then run the “Promise.all()” method.

let longTask = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Doing the task for ${value}`)
      resolve({ value: value * 10 });
    }, Math.random()*100);
  })
};

let promises = [];
promises.push(longTask(1));
promises.push(longTask(2));
promises.push(longTask(3));
promises.push(longTask(4));

Promise.all(promises).then(results => {
  for (let result of results) {
    console.log(`result: ${result.value}`);
  }
});

 

6. Racing

Another async scenario is the racing. When any of multiple tasks is completed, it returns the result of the first completed task. All other tasks are ignored. The “Promise.race()” method is used.

let longTask = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(`Doing the task for ${value}`)
      resolve({ value: value * 10 });
    }, Math.random()*100);
  })
};

let promises = [];
promises.push(longTask(1));
promises.push(longTask(2));
promises.push(longTask(3));
promises.push(longTask(4));

Promise.race(promises).then(result => {
  console.log(`result: ${result.value}`);
});

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s