PROMISES IN JAVASCRIPT
A promise is an object that stores the state of an asynchronous operation.
This note explains promises in simple language.
You will learn:
- what a promise is
- what promise states are
- how to create a promise
- what
resolveandrejectdo - how
then()works - how
catch()works - how
finally()works - what promise chains are
1. What is a promise?
A promise is an object that stores the state of an asynchronous operation.
It is like a wrapper for a result that is not ready yet when the promise is created.
Instead of getting the final value immediately, you get a promise that the value will appear later.
Easy real-life idea
Imagine someone promises to bake a cake in two weeks.
- maybe the cake will be ready
- maybe something will go wrong
- right now, you do not know the final result yet
A JavaScript promise works in a similar way.
Diagram 1. Main idea of a promise
Start async operation
-> result is not ready yet
-> JavaScript gives you a Promise object
-> later you get success or error
A promise is not the final value. A promise is an object that represents the future result of an asynchronous operation.
2. Promise states
A promise can be in three states:
- pending
- fulfilled
- rejected
Pending
This is the initial state. The promise was created, but the asynchronous operation has not finished yet.
Fulfilled
The operation finished successfully, and the promise received a value.
Rejected
The operation failed, and the promise received an error.
Diagram 2. Promise lifecycle
Promise created
-> Pending
|- success -> Fulfilled
`- error -> Rejected
A promise always starts as pending. Later it becomes either fulfilled or rejected. After that, it stays in that state forever.
3. What does "settled" mean?
When a promise is no longer pending, it is called settled.
That means:
- fulfilled
- or rejected
Important: settled is not a separate state. It is just a common word for a finished promise.
Diagram 3. Settled meaning
Pending
-> Fulfilled or Rejected
-> Settled
4. Creating a promise
A promise is created with:
const promise = new Promise((resolve, reject) => {
// asynchronous operation
});
The Promise class takes a function called the executor. This function runs immediately when the promise is created.
Inside it, you usually start some asynchronous work.
When that work finishes, you call:
resolve(value)if everything went wellreject(error)if something went wrong
Diagram 4. Promise creation
new Promise((resolve, reject) => {
...
})
resolve(value) -> fulfilled
reject(error) -> rejected
resolve means success. reject means failure.
5. Example of creating a promise
const isSuccess = true;
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) {
resolve("Success! Value passed to resolve function");
} else {
reject("Error! Error passed to reject function");
}
}, 2000);
});
console.log(promise);
In this example:
- the promise starts in
pending - after 2 seconds, the code checks
isSuccess - if
isSuccessistrue, the promise becomes fulfilled - if
isSuccessisfalse, the promise becomes rejected
Diagram 5. Example flow
Promise created
-> Pending
-> wait 2 seconds
-> Check isSuccess
|- true -> resolve(...) -> Fulfilled
`- false -> reject(...) -> Rejected
6. The then() method
After creating a promise, you need a way to handle its result.
For that, use:
promise.then(onResolve, onReject);
The then() method takes two callback functions:
- the first runs if the promise is fulfilled
- the second runs if the promise is rejected
Meaning:
onResolve(value)gets the fulfilled valueonReject(error)gets the rejection error
Diagram 6. then() logic
promise.then(onResolve, onReject)
Fulfilled -> onResolve(value)
Rejected -> onReject(error)
7. Example of then()
const isSuccess = true;
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) {
resolve("Success! Value passed to resolve function");
} else {
reject("Error! Error passed to reject function");
}
}, 2000);
});
promise.then(
value => {
console.log(value);
},
error => {
console.log(error);
}
);
If the promise succeeds, the first callback runs.
If the promise fails, the second callback runs.
Diagram 7. then() example
Promise settles
|- fulfilled -> first callback
`- rejected -> second callback
8. Named functions in then()
If the callback logic becomes bigger, it is often better to create separate functions and pass them into then() by name.
That improves readability.
Example idea
const onSuccess = value => {
console.log(value);
};
const onError = error => {
console.log(error);
};
promise.then(onSuccess, onError);
9. The catch() method
In real code, then() is usually used only for success, and errors are handled separately with catch().
promise
.then(value => {
// success
})
.catch(error => {
// error
});
The catch() method runs only if the promise is rejected. Its callback receives the error. It should come after then().
Diagram 8. then() + catch()
promise
-> then(...) = success path
-> catch(...) = error path
This is the most common promise pattern in practice.
10. Example of catch()
const isSuccess = true;
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) {
resolve("Success! Value passed to resolve function");
} else {
reject("Error! Error passed to reject function");
}
}, 2000);
});
promise
.then(value => {
console.log(value);
})
.catch(error => {
console.log(error);
});
If the promise is fulfilled, catch() does not run.
If the promise is rejected, catch() runs and receives the error.
Diagram 9. catch() meaning
Promise rejected
-> catch(error) runs
11. The finally() method
Sometimes you need code that must run no matter what happened.
For that, use:
promise
.then(...)
.catch(...)
.finally(() => {
// always runs
});
The finally() method runs after the promise is settled, whether it was fulfilled or rejected. Its callback receives no arguments.
Diagram 10. finally() logic
Promise settles
|- fulfilled
`- rejected
-> finally() runs in both cases
Use finally() for logic that should always happen, for example:
- hide loader
- stop spinner
- clean up something
12. Example of finally()
const isSuccess = true;
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
if (isSuccess) {
resolve("Success! Value passed to resolve function");
} else {
reject("Error! Error passed to reject function");
}
}, 2000);
});
promise
.then(value => console.log(value))
.catch(error => console.log(error))
.finally(() => console.log("Promise settled"));
Here:
then()handles successcatch()handles errorfinally()always runs after that
13. Promise chains
A very important feature: then() returns a new promise.
That makes it possible to build chains.
Each next then() gets the value returned by the previous then() callback.
Example
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5);
}, 2000);
});
promise
.then(value => {
console.log(value); // 5
return value * 2;
})
.then(value => {
console.log(value); // 10
return value * 3;
})
.then(value => {
console.log(value); // 30
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log("finally");
});
In this chain:
- first
then()gets5 - returns
10 - second
then()gets10 - returns
30 - third
then()gets30
Diagram 11. Promise chain flow
resolve(5)
-> then(value = 5)
return 10
-> then(value = 10)
return 30
-> then(value = 30)
Each then() passes its returned value forward to the next promise in the chain.
14. What happens if there is an error in the chain?
If an error appears anywhere in the chain:
- the following
then()calls are skipped - control goes to
catch()
That is why catch() is usually placed at the end of the whole chain.
Diagram 12. Error in chain
then(...)
-> then(...)
-> error happens
-> remaining then(...) are skipped
-> catch(error)
-> finally()
15. Important rules to remember
A promise starts as pending
That is always the first state.
A promise becomes fulfilled or rejected
After that, it cannot change again.
then() handles success
The first callback of then() receives the resolved value.
catch() handles errors
It runs only for rejected promises or errors in the chain.
finally() always runs
It runs after settlement and gets no arguments.
then() returns a new promise
That is why chaining is possible.
Diagram 13. Easy memory map
Promise
|
|- Pending
|- Fulfilled
`- Rejected
then() -> success
catch() -> error
finally() -> always
16. Common beginner mistakes
Mistake 1. Thinking a promise is a function
A promise is an object, not a function.
Mistake 2. Thinking settled is a separate state
It is not a separate state. It only means fulfilled or rejected.
Mistake 3. Thinking catch() runs after success
It does not. It runs only when there is an error or rejection.
Mistake 4. Thinking finally() gets the value or error
It does not receive any arguments.
Mistake 5. Forgetting that then() returns a new promise
This is why promise chains work.
17. Easy memory rules
Promise = future result of async work
Pending = still working
Fulfilled = success
Rejected = error
resolve() = success
reject() = failure
then() = handle success
catch() = handle error
finally() = run always
18. Quick summary
- A promise is an object that stores the state of an asynchronous operation.
- A promise has three states:
pending,fulfilled, andrejected. settledmeans the promise is no longer pending.- A promise is created with
new Promise((resolve, reject) => { ... }). resolve(value)fulfills the promise with a value.reject(error)rejects the promise with an error.then()handles success.catch()handles errors.finally()runs after settlement in both success and error cases.then()returns a new promise, which allows chaining.
19. Final conclusion
If you understand these ideas:
promise
pending
fulfilled
rejected
resolve
reject
then
catch
finally
chain
then you already have a strong foundation for working with promises in JavaScript.