JavaScript Promise states and rules
Promises states
A promise can be in 1 of 3 states:
- Fulfilled: The
resolve
function was called. - Rejected: The
reject
function was called. - Pending: The
resolve
orreject
functions were not called yet. - Settled: The promise is settled if it's not pending. Settled is not a valid state of the promise, but it's a term used frequently.
Promises rules
- If the
resolve
function is called, the functionreject
will not be called. - If the
reject
function is called, the functionresolve
will not be called. - If there is more code after
resolve
orreject
, it will also be called.
new Promise((resolve, reject) => {
resolve('resolve 1');
resolve('resolve 2');
reject('reject 1');
reject('reject 2');
console.log('hey');
}).then((data) => console.log(data));
// It shows "hey" followed by "resolve 1"
// Look into micro/macrotasks to understand why order is like so.
new Promise((resolve, reject) => {
reject('reject 1');
reject('reject 2');
resolve('resolve 1');
resolve('resolve 2');
console.log('hey');
})
.then((data) => console.log(data))
.catch((e) => console.log(e));
// It shows "hey" followed by "reject1"
// Look into micro/macrotasks to understand why order is like so.
- If you throw an error instead of calling
reject
, nothing else will be executed (this is a throw rule though, not specific to Promises).
new Promise((resolve, reject) => {
reject(new Error('reject 1'));
console.log('hey');
}).catch((e) => console.log(e.message));
// It shows "hey" followed by "reject1"
new Promise((resolve, reject) => {
throw new Error('reject 1');
console.log('hey');
}).catch((e) => console.log(e.message));
// It shows "reject1"
- The function passed to the Promise is called immediately when the Promise is created.
- After the Promise is settled, it will not change anymore.
// Write this code in the browser's console
const p = new Promise((resolve, reject) => {
setTimeout(() => resolve("time's up"), 5000);
});
// If you write the code below in less than 5 seconds,
// you will have to wait for the timeout.
p.then((data) => console.log(data));
- Calling p.then().then() is different than calling p.then(), p.then()
const p = new Promise((resolve) => {
resolve(1);
});
p.then((v) => v + 1).then(console.log); // 2
p.then((v) => v + 1);
p.then(console.log); // 1
The p
Promise object doesn't change after settled. So if you don't chain the Promise, the then
on a different Promise chain is not accounted for.
This is confusing because the jQuery pattern used by many libraries works on top of a mutable object. So when using the jQuery pattern, chaining or not is the same. It's not the same with a Promise because after the Promise is settled, the Promise becomes immutable.
Flattening Promises
If you call a Promise inside another promise, both Promises will be considered the same:
var p1 = Promise.resolve(1);
var p2 = Promise.resolve(p1);
console.log(p1 === p2); // true
Questions
What's the output?
new Promise((resolve, reject) => {
resolve('res1');
resolve('res2');
console.log('boop');
}).then(console.log);
What's the output?
new Promise((resolve, reject) => {
reject('rej1');
reject('rej2');
console.log('boop');
}).then(null, console.log);
What's the output?
new Promise((resolve, reject) => {
resolve('ok');
reject('nok');
console.log('boop');
}).then(console.log, console.log);
What's the output?
const p = new Promise((resolve) => {
resolve(Math.random());
});
p.then(console.log); // 1
p.then(console.log); // 2
What's the output?
const p = new Promise((resolve) => resolve(1));
p.then((v) => v + 1).then(console.log);
What's the output?
const p = new Promise((resolve) => resolve(1));
p.then((v) => v + 1);
p.then(console.log);
What's the output?
var p1 = Promise.resolve('banana');
var p2 = Promise.resolve(p1);
console.log(p1 === p2);