Thenables
Something important to know is that a Promise returns straight away, but the result is not available straight away. Promises are also known as thenables, because you need to register a callback with its then() method once the data has been received, like so:
const promise = new Promise((resolve, reject) => {
// either call resolve() if we have a success or reject() if it fails
});
// the 'promise' variable points to a construct
// that will eventually contain a value
promise((data) => { // <- registering a callback on then()
// our data has arrived at this point
})
In the preceding code, we demonstrated how to create a promise and how to register it with the then() method. The promise variable instance contains a construct that is returned straight away. The callback in the then() method gets invoked once the data is ready for us to use. In that sense, a Promise resembles a callback pattern.
A Promise is really just a wrapping around an asynchronous construct.
In short, to use Promises we need to:
- Create the promise and make sure to call resolve() or reject() when the data has arrived or an error has occurred
- Register a callback with its then() method
- Register a callback to handle errors as well, as that is the responsible thing to do
To put a promise to use, we need to instantiate it and make it part of a method, like so:
function getData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('data');
},1000);
})
}
We see that; when we instantiate a Promise object, its constructor takes two parameters, resolve and reject. Let's connect this to the states we know a promise can have, namely, pending, fulfilled, and rejected. When getData() is initially called, the promise returned and has the state pending. After a second, the promise will be fulfilled, because we called the resolve() method. Let's look at the getMoreData() method to see how we can put a Promise into a rejected state:
function getMoreData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('error from more data')
},1000);
})
}
In this case, we call the reject() method after a second. This will put the promise into a rejected state. To get the data from a promise instance, we need to call the then() method on it, like so:
promise.then( successCallback, <optional error call back> );
A promise's then() method takes two callbacks: the first callback is the data callback and the second callback is an optional error callback. Let's put this in use on our defined getData() method, like so:
getData().then( (data) => {
console.log('data', data);
})
It's clear that we can't just call getData() on the method straight away to get the data, but we need to call .then() on the promise it returns. Once we provide a callback, we are able to get the data and deal with it as we see fit.