Everything About JavaScript Promise
Details on Promise definitions, Promise async and await, Promise Concurrency, and Promise Usages

Promise Definitions
A Promise is an object representing the eventual completion or failure of an asynchronous operation. A Promise is in one of these states:
- pending: It is the initial state, neither fulfilled nor rejected.
- fulfilled: It means that the operation has completed successfully.
- rejected: It means that the operation has failed.
A Promise is said to be settled if it is either fulfilled or rejected, but not pending. A Promise is created by a function with two callbacks, resolve and reject. A Promise instance's Promise.prototype.then() method takes up to two arguments: the first argument is a callback function for the fulfilled case of a Promise, and the second argument is a callback function for the rejected case. It also means that Promises are thenable.
Here is a Promise example:
function promiseCall() {
// two callbacks, resolve and reject
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(1); // the case of resolve
} else {
reject(0); // the case of reject
}
}, 300); // with 300 milliseconds delay
});
// then method
myPromise.then(value => console.log(`Resolved to ${value}`),
error => console.log(`Rejected with value ${error}`) );
}
// call promiseCall 5 times
promiseCall();
promiseCall();
promiseCall();
promiseCall();
promiseCall();Each execution returns a random result, and the following result comes from one of the executions:
Resolved to 1
Resolved to 1
Rejected with value 0
Resolved to 1
Rejected with value 0A Promise instance’s Promise.prototype.catch() method schedules a function to be called when a promise is rejected. It is a shortcut for Promise.prototype.then(undefined, onRejected).
A Promise instance’s Promise.prototype.finally() method schedules a function to be called when a Promise is settled.
The then, catch, and finally methods return an equivalent Promise object that allows us to chain calls to other promise methods.
Here is the modified example that chains then, catch, and finally methods:
function promiseCall() {
// two callbacks, resolve and reject
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(1); // the case of resolve
} else {
reject(0); // the case of reject
}
}, 300); // with 300 milliseconds delay
});
// then, catch, and finally methods
myPromise.then(value => console.log(`Resolved to ${value}`))
.catch(error => console.log(`Rejected with value ${error}`))
.finally(() => console.log('Done'));
}
// call promiseCall 5 times
promiseCall();
promiseCall();
promiseCall();
promiseCall();
promiseCall();
The following result comes from one of the executions:
Resolved to 1
Done
Resolved to 1
Done
Resolved to 1
Done
Resolved to 1
Done
Rejected with value 0
DonePromise async and await
The async keyword provides a cleaner style for Promise, avoiding the need to explicitly configure Promise chains. Adding async at the start of a function makes it an async function, where we can use the await keyword before a Promise call. The code waits until the Promise is settled, at which point the fulfilled value of the Promise is treated as a return value, or the rejected value is thrown.
Here is the previous example by using async and await.
async function promiseCall() {
// two callbacks, resolve and reject
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(1); // the case of resolve
} else {
reject(0); // the case of reject
}
}, 300); // with 300 milliseconds delay
});
try {
// await result
const value = await myPromise;
console.log(`Resolved to ${value}`);
} catch (error) { // catch error, including rejected call
console.log(`Rejected with value ${error}`);
} finally { // execute final calls
console.log('Done');
};
}
// call promiseCall 5 times
promiseCall();
promiseCall();
promiseCall();
promiseCall();
promiseCall();The following result comes from one of the executions:
Rejected with value 0
Done
Rejected with value 0
Done
Rejected with value 0
Done
Resolved to 1
Done
Resolved to 1
DoneThe Promise.resolve() static method resolves a given value to a Promise. The Promise.reject() static method returns a Promise object that is rejected with a given reason.
The async function* declaration defines an async generator function, which returns an AsyncGenerator object. Here is an example of the async generator function:
// an async generator function
async function* build() {
// yield pauses the execution util the generator calls
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
yield await Promise.resolve(4);
yield await Promise.resolve(5);
}
// loop through the async generator function
for await (const value of build()) {
console.log(value);
}Here is the execution result:
1
2
3
4
5
undefinedPromise Concurrency
Promise has four static methods to facilitate async task concurrency:
Promise.all(): It fulfills when all of the promises fulfill, or rejects when any of the promises rejects.
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
.then(values => console.log(values)); // [1, 2, 3]
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)])
.then(undefined, error => console.log(error)); // 3Promise.any(): It fulfills when any of the promises fulfills, or rejects when all of the promises reject.
Promise.any([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)])
.then(values => console.log(values)); // 1
Promise.any([Promise.reject(1), Promise.reject(2), Promise.reject(3)])
.then(undefined, error => console.log(error)); // AggregateError: All promises were rejectedPromise.allSettled(): It fulfills when all promises settle.
Promise.allSettled([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)])
.then(values => console.log(values));
// [
// {
// "status": "fulfilled",
// "value": 1
// },
// {
// "status": "fulfilled",
// "value": 2
// },
// {
// "status": "rejected",
// "reason": 3
// }
// ]
Promise.allSettled([Promise.reject(1), Promise.reject(2), Promise.reject(3)])
.then(values => console.log(values));
// [
// {
// "status": "rejected",
// "reason": 1
// },
// {
// "status": "rejected",
// "reason": 2
// },
// {
// "status": "rejected",
// "reason": 3
// }
// ]Promise.race(): It settles when any of the promises settles.
Promise.race([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)])
.then(values => console.log(values)); // 1
Promise.race([Promise.reject(1), Promise.resolve(2), Promise.reject(3)])
.then(undefined, error => console.log(error)); // 1Promise Usages
We have explained details on Promise definitions, Promise async and await, and Promise Concurrency. Let’s see some Promise Usages.
Calculate sum of all Promise values
Given a list of Promises that resolves to integers, calculate sum of all resolved values.
The following is the code of implementation:
function sumOfPromises (promises) {
// sumarize all resolved values
return promises.reduce(async(sum, promise) => await sum + await promise, 0);
};
// example of three resolved integers
sumOfPromises([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]).then(console.log); // 6What if some Promises do not resolve to integers? We ignore them:
function sumOfPromises (promises) {
return promises.reduce(async(sum, promise) => {
const newValue = await promise;
return Number.isInteger(newValue) ? await sum + newValue : sum;
}, 0);
};
// example of three resolved integers or strings
sumOfPromises([
Promise.resolve(1),
Promise.resolve('a'),
Promise.resolve(3)
]).then(console.log); // 4What if some Promises are rejected? We catch the error and ignore them:
function sumOfPromises (promises) {
return promises.reduce(async(sum, promise) => {
try {
const newValue = await promise;
// ignore non-integer value
return Number.isInteger(newValue) ? await sum + newValue : sum;
} catch (e) {
return sum; // do nothing for rejected promise
}
}, 0);
};
// example of one reject value and three resolved integers or strings
sumOfPromises([
Promise.reject(1),
Promise.resolve('a'),
Promise.resolve(3),
Promise.resolve(4)
]).then(console.log); // 7Execute an asynchronous function with the time limit
Given an asynchronous function fn and a time t in milliseconds, return a new time limited version function that follows the following rules:
- If the
fncompletes within the time limit oftmilliseconds, the time limited function should resolve with the result. - If the execution of the
fnexceeds the time limit, the time limited function should reject with the error,"Exceed time limit".
This can be accomplished by Promise.race(), which settles either when fn completes or the time limit is reached.
function timeLimitedFuntion(fn, t) {
return async function(...args) {
// race two promises: the function call and the time limit
return Promise.race([fn(...args), new Promise((_, reject) =>
setTimeout(() => reject('Exceed time limit'), t))]);
}
};
// an example of fn with the execution timer and two values to be summerized
const fn = (t, a, b) => new Promise(async (resolve) => {
await setTimeout(() => resolve(a + b), t);
});
// fn completes at 50, before the time limit, 100
timeLimitedFuntion(fn, 100)(50, 10, 20).then(console.log); // 30
// fn is assumed to complete at 150, but the time limit, 100, has been reached
timeLimitedFuntion(fn, 100)(150, 10, 20).catch(console.log); // Exceed time limitWrite an asynchronous sleep function
Write an asynchronous sleep function that waits for a specific time t milliseconds.
async function sleep(t) {
// resolve the promise at the specific time t
return new Promise((resolve) => setTimeout(resolve, t));
}
const t = Date.now(); // current time
await sleep(100); // sleep for 100
console.log(Date.now() - t); // elapsed time
await sleep(200); // sleep for 200
console.log(Date.now() - t); // elapsed timeThe following result comes from one of the executions:
111 318
Build a Promise pool
A promisePool is the pool that executes n Promises simultaneously. Given an array of asynchronous functions functions and a pool limit n, build a Promise pool that returns a Promise that resolves when all the input functions resolve.
async function promisePool (functions, n) {
// result of all resolved promise values
const results = [];
async function evaluateNext() {
// all functions have been called
if (functions.length === 0) {
return;
}
// get the first function in the list
const fn = functions.shift();
// await for the fn result
const result = await fn();
// push the result into result
results.push(result);
// execute the next function
await evaluateNext();
}
// start first n function calls
await Promise.all(Array(n).fill().map(evaluateNext));
// resolve all results
return Promise.resolve([results]);
}
async function sleep(t) {
// resolve the promise at the specific time t with the value t
return new Promise((resolve) => setTimeout(() => resolve(t), t));
}
const t = Date.now(); // current time
// execute 3 promise calls with the pool size of 2
const results = await promisePool([() => sleep(100), () => sleep(200), () => sleep(110)], 2);
// display resolved results and the elapsed time
console.log(results, Date.now() - t);The following result comes from one of the executions:
[100, 200, 110]
227Conclusions
We have walked through details on Promise definitions, Promise async and await, Promise Concurrency, and Promise Usages. Hopefully, it helps you to get a deeper understanding of Promises.
Thanks for reading.
Want to Connect?
If you are interested, check out my directory of web development articles.More content at PlainEnglish.io.
Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord.





