All 4 Flavours of Promises in Javascript

Promise.all Promise.any Promise.allSettled Promise.race

Photo by Safar Safarov on Unsplash
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)
p1.then(callback).catch(errorCallback)

Flavour 1: Promise.all()

function asyncTask(message, delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(message);
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.all([task1, task2, task3, task4]).then(function (results) {
console.log(results);
});

// results will contain:
Array(4) [ "Task 1 Done", "Task 2 Done", "Task 3 Done", "Task 4 Done" ]

Key takeaways about Promise.all()

  1. Time take to finish all promises is equal to the largest time consuming promise.
    In above passed tasks, task4 is taking most the time, hence total time taken by the Promise.all() is 5000 ms .
  2. If any promise in the passed list got rejected then the catch block is directly called, not matter if all other Promises got resolved or not.
function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (message === "Task 3 Done") {
// Rejecting third task
reject("Error occured");
} else {
resolve(message);
}
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.all([task1, task2, task3, task4])
.then(function (results) {
// this will never be called
console.log(results);
})
.catch(function (error) {
console.log(error);
});

// In the console Error occured will be printed.

Flavour 2: Promise.allSettled()

function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (message === "Task 3 Done") {
reject("Error occured");
} else {
resolve(message);
}
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 3000);
const task3 = asyncTask("Task 3 Done", 1000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.allSettled([task1, task2, task3, task4])
.then(function (results) {
console.log(results);
})

// console.log(results) output;
0: Object { status: "fulfilled", value: "Task 1 Done" }

1: Object { status: "fulfilled", value: "Task 2 Done" }

2: Object { status: "rejected", reason: "Error occured" }

3: Object { status: "fulfilled", value: "Task 4 Done" }

Key takeaways about Promise.allSettled()

  1. Unlike Promise.all(), it does not short circuit if any promise got rejected. It will keep executing other promises until all of the passed promises either got rejected or resolved.
  2. catch block is never get called in Promise.allSettled because all the data is returned in then block with the information of rejected and resolved promises.
function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject("Error occured");
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);

Promise.allSettled([task1])
.then(function (results) {
console.log(results);
// above line will log
// [{ status: "rejected", reason: "Error occured" }]
})
.catch(function (error) {
console.log(error); // It will never get called.
});

Flavour 3: Promise.race()

function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (message === "Task 3 Done") {
reject("Error occured");
} else {
resolve(message);
}
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 2000);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.race([task1, task2, task3, task4])
.then(function (result) {
console.log(result); // Task 2 Done will be logged in the console
// Here Task2 has shortest time, so it will win the race.
// Here result will not be an array.
// result will be the data returned by resolve method
})

What if a rejected promise wins the race?

function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (message === "Task 3 Done") {
reject("Error occured");
} else {
resolve(message);
}
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200); // Shortest time 200ms
const task4 = asyncTask("Task 4 Done", 5000);

Promise.race([task1, task2, task3, task4])
.then(function (results) {
console.log(results);
})
.catch(function (error) {
console.log(error); // Task 3 has shortest time, and it wins the race.
// Error occured will be logged in the console.
});

Flavour 4: Promise.any()

function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (message === "Task 3 Done") {
reject("Error occured");
} else {
resolve(message);
}
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200); // Winner Tasks, but it's being rejected
const task4 = asyncTask("Task 4 Done", 5000);

Promise.any([task1, task2, task3, task4])
.then(function (results) {
console.log(results); // Task 2 Done will be logged in the console.
// Task 2 will win the race, because runner (Task3)
})
function asyncTask(message, delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject("Error occured"); // Passed error message won't be available in catch block.
}, delay);
});
}

const task1 = asyncTask("Task 1 Done", 2000);
const task2 = asyncTask("Task 2 Done", 1000);
const task3 = asyncTask("Task 3 Done", 200);
const task4 = asyncTask("Task 4 Done", 5000);

Promise.any([task1, task2, task3, task4])
.then(function (results) {
console.log(results);
})
.catch(function (error) {
console.log("error", error);
// error: AggregateError: All promises were rejected
});

Key takeaways about Promise.any()

  1. Whatever we pass in reject message, won’t be available in catch block.
  2. If all promise got rejected, it will throw a predefined error
    AggregateError: All promises were rejected
// Can you Guess what will be printed in the console in case we have empty
// array passed inside all 4 variants of Promises?

Promise.all([])
.then(function (data) {
console.log("then block all", data);
})
.catch(function () {
console.log("then block allSettled");
});

Promise.allSettled([])
.then(function (data) {
console.log("then block allSettled", data);
})
.catch(function (error) {
console.log("then block allSettled");
});

Promise.any([])
.then(function () {
console.log("then block any");
})
.catch(function (error) {
console.log("catch block any", error);
});

Promise.race([])
.then(function () {
console.log("then block race");
})
.catch(function (error) {
console.log("catch block race");
});
then block all,  Array [] => In case of Promise.all()

then block allSettled , Array [] => In case of Promise.setteled()

catch block any AggregateError: No Promise in Promise.any was resolved

For Race, nothing will be logged.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store