In our starter files, open the index.html page from this lessons folder:
10.Async-JavaScript > 04.The-promise-constructor
In the previous lesson, we could use promises because the Fetch API
returns a Promise
. But what about functions that don’t return a Promise
?
To begin, we have an empty starter file. Let’s write a simple custom function, this will set a name property to a data object after a timeout:
let data = {};
function getData() {
setTimeout(function () {
data = { name: 'Chris' };
}, 2000);
}
getData();
console.log(data.name); // undefined
The result in the console is undefined
because we access the empty data
object immediately, but the data
takes two seconds to be set.
This is like a simulated request to a database, we need to handle what happens between requesting the data and receiving it. We know promises are good for this, but this function does not return a promise by default.
For this we can create our own using the promise constructor.
Constructors are something we have already used with the new
operator. We have looked at:
new Array()
new Object()
new Function()
These all created a new instance of an Object. Promises are objects too, so we can also use the new
operator to create a new Promise.
First, comment out this example, except the data variable:
let data = {};
// function getData() {
// setTimeout(function () {
// data = { name: 'Chris' };
// }, 2000);
// }
// getData();
// console.log(data.name);
Then create a new Promise
below:
let data = {};
// function getData() {
// setTimeout(function () {
// data = { name: 'Chris' };
// }, 2000);
// }
// getData();
// console.log(data.name);
new Promise()
This constructor takes in a function:
new Promise(function () {
})
And this function takes two optional parameters. A function to run if the promise resolves, and one for a rejection:
new Promise(function (resolve, reject) {
})
These are names of our choice, but resolve
and reject
are descriptive. Since this is our own custom Promise, we set when we want the resolve
and reject
functions to run.
resolve
functionLet’s begin with resolve:
// 1. store promise in variable to call when required:
const promise = new Promise(function (resolve, reject) {
// 2. for now, simply resolve the promise
resolve();
});
// 3. use the promise variable to call the then(), catch(), and finally() methods:
promise.then(function () {
console.log('success');
})
promise.catch(function (error) {
console.log(error);
});
The result in the logs should be success
.
This resolve function can also receive a fulfilment value to pass on:
const promise = new Promise(function (resolve, reject) {
resolve('SUCCESS');
});
And this return value is then available in the following then()
function:
const promise = new Promise(function (resolve, reject) {
resolve('SUCCESS');
});
promise.then(function (response) {
console.log(response); // SUCCESS
});
promise.catch(function (error) {
console.log(error);
});
Going back to the earlier example of fetching data we commented out. Copy and paste the setTimeout
into the Promise
function:
const promise = new Promise(function (resolve, reject) {
// paste setTimeout from previous example
setTimeout(function () {
data = { name: "Chris" };
}, 2000);
resolve("SUCCESS");
});
Then move the resolve
function to be inside the setTimeout. This will run after the data
has been set:
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
data = { name: 'Chris' };
resolve('SUCCESS');
}, 2000);
});
This now means the Promise
should only be resolved after the data
has been set. Test this by logging the data
:
promise.then(function (response) {
console.log(response);
console.log(data);
});
But what about rejecting?
reject
functionThis is our custom promise, and we can make it whatever we want. For this example, we will successfully resolve if the name property has been set, and reject if the data
object is empty. Modify the code inside the setTimeout
as follows:
const promise = new Promise(function (resolve, reject) {
setTimeout(function () {
data = { name: "Chris" };
if (Object.keys(data).length > 0) {
resolve("success");
}
reject("rejected");
}, 2000);
});
If a function by default does not return a Promise
, we can create our own. We do this with the Promise()
constructor. This can resolve
or reject
at any point we feel it should, we have total control over the behaviour.