- .then()
- Reject()
- Chaining operations using Promises
A
Promise is a built-in JavaScript object that represents a value that will be ready in the future.We can create a Promise like this:
const promise = new Promise((resolve, reject) => { // Do something that takes time here... resolve("It worked!") // This means everything went OK })
The
new Promise() part creates the promise.Inside it, we give it a function with two parameters:
resolve is a function we call when everything is successful
reject is a function we call if something goes wrongIn the example above, we just resolve it immediately with the message
"It worked!"..then()
To do something after the promise is done, we use
.then():const promise = new Promise((resolve, reject) => { // Do something that takes time here... resolve(100) // This means everything went OK }) promise.then(result => { console.log("The result is:", result) })
This prints:
The result is: 100
The value we passed to
resolve() gets sent to the function inside .then() as result.Let’s simulate a task that takes 2 seconds using
setTimeout:const delayedPromise = new Promise( (resolve, reject) => { setTimeout( () => resolve("Done waiting!"), 2000 ) }) delayedPromise.then(result => console.log(result))
This will wait 2 seconds and then print:
Done waiting!
reject()
Let’s create a promise that fails:
const failingPromise = new Promise((resolve, reject) => { reject("Something went wrong") })
Now if we use
.then() on this, nothing will happen, because .then() only handles success.To handle errors, we use
.catch():const failingPromise = new Promise((resolve, reject) => { reject("Something went wrong") }) failingPromise .then( result => console.log("This will NOT run:", result) ) .catch( error => console.log("Caught an error:", error) )
This prints only
Caught an error: Something went wrong
The value passed to
reject() is sent to the .catch() function.Let’s build a Promise that sometimes works and sometimes fails, based on some condition.
function checkNumber(n) { return new Promise((resolve, reject) => { if (n > 0) { resolve("Positive number") } else { reject("Not a positive number") } }) }
Now we can call this and handle both cases:
checkNumber(5) .then( msg => console.log("Success:", msg) ) .catch( err => console.log("Failure:", err) )
This prints:
Success: Positive number
And if we try with a different number:
checkNumber(-1) .then( msg => console.log("Success:", msg) ) .catch( err => console.log("Failure:", err) )
It prints:
Failure: Not a positive number
Chaining operations using Promises
We can rewrite our earlier example using
Promise, and it will look much cleaner.Let’s start by writing a new version of our doubling function, but this time, it returns a promise:
function doubleNumbers(numbers) { return new Promise(resolve => { // Wait 1 second before doing the operation setTimeout(() => { const doubled = numbers.map(n => n * 2) resolve(doubled) // Return the result using resolve }, 1000) }) }
Now we can use
.then() to tell JavaScript what to do with the result:function doubleNumbers(numbers) { return new Promise(resolve => { // Wait 1 second before doing the operation setTimeout(() => { const doubled = numbers.map(n => n * 2) resolve(doubled) // Return the result using resolve }, 1000) }) } const input = [1, 2, 3] doubleNumbers(input) .then( result => console.log("Doubled numbers:", result) )
This prints:
Doubled numbers: [ 2, 4, 6 ]
So far, this works the same as the callback version, but now the code is easier to extend and read.
Let’s say we want to add more steps:
- First, double all the numbers
- Then, remove numbers smaller than 4
- Finally, add them all together
We can write one function for each step, all using promises:
function doubleNumbers(numbers) { return new Promise(resolve => { // Wait 1 second before doing the operation setTimeout(() => { const doubled = numbers.map(n => n * 2) resolve(doubled) // Return the result using resolve }, 1000) }) } function filterBigNumbers(numbers) { return new Promise(resolve => { setTimeout(() => { const filtered = numbers.filter(n => n > 3) resolve(filtered) }, 1000) }) } function sumNumbers(numbers) { return new Promise(resolve => { setTimeout(() => { const total = numbers.reduce((acc, n) => acc + n, 0) resolve(total) }, 1000) }) }
Now we can chain them together like this:
const input = [1, 2, 3] doubleNumbers(input) .then(filterBigNumbers) .then(sumNumbers) .then( result => console.log("Final result after all steps:", result) )
This prints:
Final result after all steps: 10
Let’s walk through what this does:
doubleNumbersdoubles the array:[2, 4, 6]filterBigNumbersremoves anything ≤ 3:[4, 6]sumNumbersadds the remaining numbers:4 + 6 = 10- Finally, we print the result.
Each
.then() waits for the step before it to finish. So we can build a chain of actions without nesting. This makes the code more readable and easier to debug.