Consuming Promises

Promises are one approach to asynchronous programming. Functions which perform asynchronous operations (such as interacting with the file system or a database) can return a promise which is then resolved later. If that promise can't be kept (something is rejected) we can catch the error and deal with it.

then and catch

getDataFromFile()
.then((result) => {
doSomethingWithData(result)
})
.catch((err) => {
handleError(err)
})

This example is about as simple as it gets. We don't need to understand the exact details of how to return a promise in order to use getDataFromFile. We just need to expect that:

  1. The then function will call doSomethingWithData if there is no error. doSomethingWithData can be passed a value.

  2. The catch function will call handleError if there is an error, and handleError will be passed an error (often a JavaScript Error object).

If getDataFromFile returns a resolved promise, then will be called (and catch won't be). If it returns a rejected promise, catch will be called (and then won't be).

If you are familiar with callbacks, you'll notice it's like a callback that has had the err and the data handling parts separated. The same thing might be written like this with callbacks:

getDataFromFileCallback(function(err, data) {
if (err) {
console.error(err.message)
} else {
console.log(data)
}
})

Promise chains

We can also string together quite long 'promise chains' which define the order certain tasks should occur in:

getDataFromFile()
.then((uncheckedMessyData) => {
return checkTheData(uncheckedMessyData)
})
.then((messyData) => {
return modifyTheData(messyData)
})
.then((tidyData) => {
displayTheData(tidyData)
})
.catch((err) => {
handleError(err)
})

So long as each function in the chain returns a data object, this will help ensure everything takes place in the correct order. For example, displayTheData always gets called after modifyTheData.