JavaScript Promises

A promise in JavaScript is exactly what it sounds like - you use it to make a promise to do something, usually asynchronously.

Wed Mar 02 2022

JavaScript Promises

A promise in JavaScript is exactly what it sounds like - you use it to make a promise to do something, usually asynchronously. When the task completes, you either fulfill your promise or fail to do so.

Creating a promise

Promise is a constructor function, so you need to use the new keyword to create one.

let promise = new Promise(function (resolve, reject) {
  // executor
})

The function passed to new Promise is called the executor. When new Promise is created, the executor runs automatically. It contains the producing code which should eventually produce the result. It takes a function, as its argument, with two parameters - resolve and reject. These are callbacks provided by JavaScript itself.

Complete a promise using resolve and reject

The promise object returned by the new Promise constructor has these internal properties:

  • state:

    • pending
    • fulfilled
    • rejected
  • result

    • undefined
    • value
    • error

The result:- initially undefined, then changes to value when resolve(value) called or error when reject(error) is called.

The state:- initially “pending”, then changes to either “fulfilled” when resolve is called or “rejected” when reject is called.

The promise we created in the above code is forever stuck in the pending state because we did not add a way to complete the promise.

When the executor obtains the result, be it soon or late, doesn’t matter, it should call one of these callbacks:

resolve(value) — if the job is finished successfully, with result value.

reject(error) — if an error has occurred, error is the error object.

let done = true

const isItDoneYet = new Promise((resolve, reject) => {
  if (done) {
    const workDone = 'Here is the thing I built'
    resolve(workDone)
  } else {
    const why = 'Still working on something else'
    reject(why)
  }
})

The example above uses strings for the argument of these functions, but it can really be anything. Often, it might be an object, that you would use data from, to put on your website or elsewhere.

So to summarize: the executor runs automatically and attempts to perform a job. When it is finished with the attempt, it calls resolve if it was successful or reject if there was an error.

Consuming a promise

In the last section, we introduced how a promise is created. Now, let’s see how the promise can be consumed or used.

const isItDoneYet = new Promise(/* ... as above ... */)
//...

const checkIfItsDone = () => {
  isItDoneYet
    .then(result => {
      console.log(result)
    })
    .catch(err => {
      console.error(err)
    })
}

then

The argument of .then is a function that runs when the promise is resolved, and receives the result.

catch

The argument of .catch is a function that runs when the promise is rejected, and receives the error.

The call .catch(err) is a complete analog of .then(null, err), it’s just a shorthand.

isItDoneYet.then(
  result => console.log(result),
  err => console.error(error)
)

finally

The finally() method is always executed whether the promise is fulfilled or rejected. In other words, the finally() method is executed when the promise is settled.

isItDoneYet
    .then(result => { ...})
    .catch(error => { ... })
    .finally(() => { ... })

In the finally() method, you can place the code that cleans up the resource when the promise is settled, regardless of its outcome.

By using the finally() method, you can avoid duplicate code in the then() and catch() methods like this:

isItDoneYet
  .then(result => {
    // process the result
    // clean up the resources
  })
  .catch(error => {
    // handle the error
    // clean up the resources
  })

Now, you can move the clean up the resources part to the finally() method as follows:

promise
  .then(result => {
    // process the result
  })
  .catch(error => {
    // handle the error
  })
  .finally(() => {
    // clean up the resources
  })

A finally handler has no arguments. In finally we don’t know whether the promise is successful or not. That’s all right, as our task is usually to perform “general” finalizing procedures.

Leave a comment

To make a comment, please send an e-mail using the button below. Your e-mail address won't be shared and will be deleted from our records after the comment is published. If you don't want your real name to be credited alongside your comment, please specify the name you would like to use. If you would like your name to link to a specific URL, please share that as well. Thank you.

Comment via email
Dibin Jose
Dibin Jose

Software Engineer at Lightrains Tech

Tags Recent Blogs