Promises

Promises can be in the following states:

  • fullfilled
  • rejected
  • pending

How to create promise:

const myPromise = new Promise((resolve, reject) => {
  if (condition) {
    resolve('Stuff worked');
  } else {
    reject("Error, it's broken");
  }
});

myPromise
  .then(result => console.log(result))
  .catch(err => console.log('Error: ', err));

Merge Promises

const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'Message 1');
});

const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 1000, 'Message 2');
});

const promise4 = new Promise((resolve, reject) => {
  setTimeout(resolve, 3000, 'Message 3');
});

Promise.all([promise2, promise3, promise4]).then((result) =>
  console.log('Result', result)
);

The result is an array of messages.

ES8 - Async/Await

It’s just a syntax sugar over promises.

Example of code with promises:

movePlayer(100, 'Left')
  .then(() => movePlayer(200, 'Right'))
  .then(() => movePlayer(300, 'Left'))
  .then(() => movePlayer(150, 'Left'));

This could be transformed into async function the following way:

async function playerStart() {
  const firstMove = await movePlayer(100, 'Left');
  await movePlayer(200, 'Right');
  await movePlayer(300, 'Left');
  await movePlayer(150, 'Left');
}

It make the code easier to read.

There is more realistic with error handling:

const urls = [
  'https://random-data-api.com/api/address/random_address',
  'https://random-data-api.com/api/app/random_app',
  'https://random-data-api.com/api/business_credit_card/random_card',
];

// Promise.all(urls.map((u) => fetch(u).then((resp) => resp.json())))
//   .then(([address, app, card]) => console.log(address, app, card))
//   .catch((err) => console.log('Error: ', err));

const getData = async function () {
  try {
    const [address, app, card] = await Promise.all(
      urls.map((u) => fetch(u).then((resp) => resp.json()))
    );
    console.log(address, app, card);
  } catch (err) {
    console.log('Error', err);
  }
};

getData();

ES9 (ES2018) Async

finally

myPromise
  .then(result => console.log(result))
  .catch(err => console.log('Error: ', err))
  .finally(() => ...);

for await of

const getData = async function () {
  const arrayOfPromises = urls.map((url) => fetch(url));
  for await (let request of arrayOfPromises) {
    const data = await request.json();
    console.log('ASD', data);
  }
};

getData();

Job Queue

Consider the following code:

setTimeout(() => console.log('Message 1'), 0);
setTimeout(() => console.log('Message 2'), 10);

Promise.resolve('hi').then((e) => console.log('Message 3'));

console.log('Message 4');

Console log result is the following:

Message 4
Message 3
Message 1
Message 2

The reason is that Promises is a part of JS. It’s work using Job Queue, or Microtask Queue. This queue has a higher priority than the Callback queue.

Parallel, Sequence and Race

Sequence is just a set of await. Race is a Promise.race([...]). And finally parallel is a Promise.all([...])

ES2020 allSettled

Promise.allSettled([promise2, promise3, promise4]).then((result) =>
  console.log('Result', result)
);

It will return an array with items, each of them has a status (fullfilled | rejected) & value or reason fields. ES2021 contains also Promise.any([]) method, which will return only those results, which is fullfilled.