DEV Community

loading...
Cover image for Promises in Javascript

Promises in Javascript

geoffreyianward profile image Geoffrey Ward ・2 min read

Javascript is, by default, single threaded. This means that it must deal with all operations synchronously, one at a time. This isn't ideal, as there are often times we want to do many different operations at once. This is known as performing tasks asynchronously.

Promises are a way of dealing with asynchronous operations within Javascript. They are best utilized when dealing with multiple asynchronous calls, as these can lead to 'callback hell', an unmanageable state that is prone to errors. Promises improve on the traditional event callbacks in a few significant ways. They improve readibility significantly. They are more honest with their flow of control, which makes them more efficient with handling asynchronous tasks. Promises are also clearer and more efficient when it comes to catching and logging errors.

There are 4 main states in a Promise:

  • fulfilled: Action related to the promise succeeded
  • rejected: Action related to the promise failed
  • pending: Promise is still pending i.e not fulfilled or rejected yet
  • settled: Promise has fulfilled or rejected

The Parameters of a Promise:

  • Promise takes one argument, a callback function.
  • The callback function takes two arguments, resolve and reject
  • successful conditions will trigger a resolve
  • if there is an error, this triggers reject

We can look at the functionality of a promise through this syntax:

var promise = new Promise(function(resolve, reject) {
  // do a thing, possibly async, then…

  if (/* successful condition */) {
    resolve("Success!");
  }
  else {
    reject(Error("Failure!"));
  }
});

This represents a single condition Promise. This works perfectly fine on its own, but where promises really start to shine is when we start chaining multiple conditions together. So let's look at chaining!

Using .then, we can chain multiple steps together to form multiple tasks. Each .then stage represents a task we want the promise to execute. We put a caboose on the end of the chain, marked as .catch, which will handle the errors for all of the conditions chained before it. This type of simplicity and readability is at the core of why people are drawn to using promises.

Here is a promise with an exceptionally long chain. Even with all these steps, the promise still retains a surprising amount of readability:

asyncThing1().then(function() {
  return asyncThing2();
}).then(function() {
  return asyncThing3();
}).catch(function(err) {
  return asyncRecovery1();
}).then(function() {
  return asyncThing4();
}, function(err) {
  return asyncRecovery2();
}).catch(function(err) {
  console.log("Don't worry about it");
}).then(function() {
  console.log("All done!");
})

Even with all the different asynchronous operations happening in the promise above, we can still follow along with the promise as it parses through its asynchronous tasks.

These are just some of the many uses of Javascript promises. Now that promises are part of the native javascript environment, we can look forward to seeing them implemented more and more.

Discussion

pic
Editor guide