Asyncronous operations is one of the hardest topics for a beginner programmer. In this article, we're aiming to explain how to use them via JavaScript promises and make it very easy to use.

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
MDN website

A Simple Promise

To replicate the asyncronous nature of a real scenario code, we're going to use the setTimeout function to delay the flow.

Here is out first promise:

const prom = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("The return string");
  }, 1000);
});

Notice that the `Promise` constructor takes, as parameter, a function with 2 parameters of its own: `resolve` and `reject`.

The `resolve` string will be passed on the `then` method:

prom.then(text => {
  console.log(text)
});

For the cases when a promise is rejected, a `catch` method is used. The third method we can use is `finally` which always run no matter if the promise is resolved or rejected.

Here is a full example for completeness. We're using:

  • setInterval to run the code every 2 seconds
  • `Math.random()` to randomly generate a random value and `resolve` or `reject` based on it
setInterval(() => {
  console.log('Start:')
  const prom = new Promise((resolve, reject) => {
    setTimeout(() => {
      let rand = Math.random();
      if( rand > 0.5) {
        resolve(`Resolved: ${rand}`);
      } else {
        reject(`Rejected: ${rand}`);
      }
    }, 1000);
  });
  prom.then(text => {
    console.log(`  - then: ${text}`);
  }).catch(reason => {
    console.log(`  - catch: ${reason}`);
  }).finally(() => {
    console.log(`  - finally`);
  });
}, 2000);

Concurency

A very common scenario is loading multiple resources simultaneously but displaying them only once all are completed. This can be easily achieved with `Promise.all`.

In the example below, we have 3 promises: `prom1`, `prom2` and `prom3` that resolve at different intervals: 1500, 500 and 2000 respectively:

const prom1 = new Promise((resolve) => {
  setTimeout(() => {
    resolve("Resolved 1!");
  }, 1500);
});
const prom2 = new Promise((resolve) => {
  setTimeout(() => {
    resolve("Resolved 2!");
  }, 500);
});
const prom3 = new Promise((resolve) => {
  setTimeout(() => {
    resolve("Resolved 3!");
  }, 2500);
});
Promise.all([prom1, prom2, prom3])
  .then( ([text1, text2, text3]) => {
    console.log(`then: ${text1} | ${text2} | ${text3}`);
  });

Notice that the "then: Resolved 1! | Resolved 2! | Resolved 3!" is only shown after 2.5 seconds when all promises are resolved.

Dependency

Another very common case is chaining promises - that is having 2 promises that depend on each over. Eg: retrieving a list of resources and then details of a particular resource:

function firstOperation() {
  const prom = new Promise((resolve) => {
    setTimeout(() => {
      resolve("Resolved 1!");
    }, 1500);
  });
  prom.then(text => {
    console.log(` - Resolved: ${text}`)
    secondOperation();
  });
};


function secondOperation() {
  const prom = new Promise((resolve) => {
    setTimeout(() => {
      resolve("Resolved 2!");
    }, 1500);
  });
  prom.then(text => {
    console.log(` - Resolved: ${text}`)
  });
};

firstOperation();

What next?

There are lots of great resources available to learn from. Probably the best start is the MDN docs.