Javascript Promises

Javascript Promises

A Promise is an object which is used to find out if the asynchronous operation is completed or not.

The Promise object has two properties: state and result.

State:

  • pending: initial state, neither fulfilled nor rejected.

  • fulfilled: meaning that the operation was completed successfully.

  • rejected: meaning that the operation failed.

Result:

  • undefined: we get this value when the promise is pending.

  • a result value: we get this value when the promise is fulfilled.

  • an error object: we get this value when the promise is rejected.

A promise is said to be settled if it is either fulfilled or rejected, but not pending.

Creating a Promise

A Promise object is created using the new keyword and its constructor. This constructor takes a function, called the executor function, as its parameter.

This executor function takes two functions as parameters.

  • resolve - It is called when the task completes successfully and returns the results of the task as a value.

  • reject - It is called when the task fails and returns the reason for failure, which is typically an error object.

resolve & reject are built-in javascript callbacks. We can name them differently also like myResolve & myReject.

const p1 = new Promise(function(resolve,reject){
    let data = true
    if(data){
        setTimeout(()=>resolve("Data fetched"), 3000)
    }else{
        reject("Error occurred")
    }
})

Function returning Promise

function myPromise(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise()

How to use a Promise

We can consume a promise by using the then() method.

.then(fulfillmentHandler, rejectionHandler):

.then(): It can deal with the resolved case and rejected case also. It accepts two callback functions. The first callback is called when the promise is resolved successfully and the second callback is called when the promise is rejected.

.then() registers the fulfillment handler function in the onFulfillment array and the rejection handler function in the onRejection array. When a promise gets resolved, all the functions of onFulfillment array goes into microtask queue and if a promise gets rejected then all the functions of onRejection array goes into microtask queue, then from microtask queue these callback functions are sent to callstack by event loop if callstack is empty.

.then() never executes the callback functions immediately.

function myPromise(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise()

// First Callback executed because promise resolved successfully
p1.then(res=>console.log(res), err=>console.log(err)) // Data Fetched
function myPromise(){
    return new Promise(function(resolve,reject){
        let data = false
        if(data){
            setTimeout(()=>resolve("Data fetched"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise()

// Second Callback executed because promise is rejected
p1.then(res=>console.log(res), err=>console.log(err)) // Error occurred

Error Handling in Promises

catch(callback): It deals with the rejected case only. The callback is called when the promise is rejected.

function myPromise(){
    return new Promise(function(resolve,reject){
        let data = false
        if(data){
            setTimeout(()=>resolve("Data fetched"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise()

p1.catch(err=>console.log(err)) // Error occurred

Finally in a Promise

finally(): finally method always runs regardless of whether a promise is resolved or rejected.

Finally does not take any input and it doesn't return anything.

function square(){
  return new Promise(function(resolve, reject){
    resolve(2)
  })
}

square().then(function(res){
  console.log(res)
  return res
}).finally(function(res){
  console.log(res*2)
  return res*2
}).then(function(res){
  console.log(res*4)
})

/*
Output-
2
NaN
8
*/

Promise APIs

promise.all():

Promise.all([promises]) accepts an array of promises and returns a promise. If all the promises of the input array get resolved then the returned promise will be fulfilled and its resolved value will be an array containing all the resolved values of input array promises, and if any one of the input array promises gets rejected then the returned promise will be rejected and its rejected value will be the rejected value of the first promise which got rejected.

let p1 = Promise.resolve("one")
let p2 = Promise.resolve("two")
let p3 = Promise.resolve("three")

Promise.all([p1,p2,p3])
.then(res=>console.log(res))
.catch(err=>console.log(err))

// [ 'one', 'two', 'three' ]

let p4 = Promise.resolve("one")
let p5 = Promise.resolve("two")
let p6 = Promise.reject("three")

Promise.all([p4,p5,p6])
.then(res=>console.log(res))
.catch(err=>console.log(err))

// three

promise.any([promises]):

Promise.all([promises]) accepts an array of promises and returns a promise. If all the promises of the input array get rejected then the returned promise will be rejected and its rejected value will be '[AggregateError: All promises were rejected]', and if any one of the input array promises gets fulfilled then the returned promise will be resolved and its resolved value will be the resolved value of the first promise which got resolved.

let p1 = Promise.resolve("one")
let p2 = Promise.resolve("two")
let p3 = Promise.reject("three")

Promise.any([p1,p2,p3])
.then(res=>console.log(res))
.catch(err=>console.log(err))

// 'one'

let p4 = Promise.reject("one")
let p5 = Promise.reject("two")
let p6 = Promise.reject("three")

Promise.any([p4,p5,p6])
.then(res=>console.log(res))
.catch(err=>console.log(err))

// [AggregateError: All promises were rejected]

promise.allSettled([promises]):

This method accepts an array of promises and waits for all promises to settle(resolve/reject) and returns their results as an array of objects.

If a promise is fulfilled then that object has two properties - status & value.

If a promise is rejected then that object has two properties - status & reason.

// Promise 1
function myPromise1(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched 1"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

// Promise 2
function myPromise2(){
    return new Promise(function(resolve,reject){
        let data = false
        if(data){
            setTimeout(()=>resolve("Data fetched 2"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

// Promise 3
function myPromise3(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched 3"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise1()
let p2 = myPromise2()
let p3 = myPromise3()

Promise.allSettled([p1,p2,p3]).then(res=>console.log(res)).catch(err=>console.log(err))

// Output
[
  { status: 'fulfilled', value: 'Data fetched 1' },
  {
    status: 'rejected',
    reason:  Error occurred
  },
  { status: 'fulfilled', value: 'Data fetched 3' }
]

promise.race([promises]):

This method accepts an array of promises and doesn't wait for all the promises to settle. It is done when any one of the promises is settled.

It returns the value of the first settled promise.

// Promise 1
function myPromise1(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched 1"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

// Promise 2
function myPromise2(){
    return new Promise(function(resolve,reject){
        let data = false
        if(data){
            setTimeout(()=>resolve("Data fetched 2"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

// Promise 3
function myPromise3(){
    return new Promise(function(resolve,reject){
        let data = true
        if(data){
            setTimeout(()=>resolve("Data fetched 3"),3000)
        }else{
            reject(new Error("Error occurred"))
        }
    })
}

let p1 = myPromise1()
let p2 = myPromise2()
let p3 = myPromise3()

Promise.race([p1,p2,p3]).then(res=>console.log(res)).catch(err=>console.log(err)) // Data fetched 1

Final Words

And that’s it for this blog.

I hope you’ve found this blog a good referencing resource and thank you for reading.

If this blog was helpful, please do like, comment and share. Thanks, see you in the next blog.✌️