The Promise
constructor is used to create a new Promise
object. It receives a single function as a parameter (known as the executor function), which in turn receives the resolve
and reject
functions as parameters:
const promise = new Promise((resolve, reject) => {
// Perform some operation, then call either resolve() or reject()
});
Within the body of the executor function, you can perform any operation — typically, an asynchronous one. You then either call resolve(value)
or reject(reason)
, depending on the outcome of that operation, to fulfill or reject the promise.
Note that the Promise
object is rejected if an error is thrown within the body of the executor function. The return value of the executor function is ignored.
Instructor: [00:00] In the previous lessons, we've seen how we can create promises using the promise.resolve and promise.reject methods. In this lesson, I want to take a look at the promise constructor. The promise constructor takes a single argument that is called the executive function.
[00:15] This function takes two parameters, the resolve and reject functions. These functions are used to either resolve or reject the promise that we're creating. Within the body of the executive function, we typically kick off some sort of asynchronous operation. Depending on the result of that asynchronous operation, we either call resolve or we call reject.
[00:37] Let's implement a promise that is automatically fulfilled after one second. We can use setTimeout. We're going to pass it a callback that is to be called after 1,000 milliseconds. Within the callback, we're going to call resolve.
[00:52] All right, let's start this promise in a variable, and let's also use the event method to register both in onFulfillment handler and in onRejection handler. This one is going to say fulfilled, and the onRejection handler is going to say rejected.
[01:12] I'm going to head over to the terminal. I'm going to execute our program. After one second, we can see that our promise has been fulfilled. Let's now test that the rejection is working as well. We're going to go back up here and instead of calling resolve, we're going to call reject. Head back to the console, run the program once again. We see the message rejected log to the console.
[01:38] We've essentially implemented sleep functionality. Why not make that a reusable function? To do that, let's first go back to calling resolve instead of reject. Next, I'm going to create a function called sleep, and it's going to accept the milliseconds that we want to sleep as a parameter.
[01:55] We can now take our promise and return it from this function. Of course, we want to use the parameter instead of the hardcoded 1,000 milliseconds. Instead of using the promise variable down here, we're now going to call sleep directly.
[02:14] We can also get rid of the Rejection handler down here, because we know that our promise is always going to be fulfilled. We can also clean up our sleep functions some more. We never call reject, so there is no need for us declare the parameter.
[02:28] We also don't pass in argument to resolve, so we can get rid of our error function here and simply pass resolve to set timeout directly. Let's make sure our refactored code is still working.
[02:40] I'm going to run our program again. That looks good. We still see the message fulfilled log to the console. Now that we've made sleep a reusable function, we can easily call it multiple times in our promise chain.
[02:54] I'm going to add another .then call to the end and I'm going to call sleep again. I'm also going to change this message to after one second, copy this then call, append it to the end, and make that two seconds here.
[03:11] Finally, I'll add one last log statement before the promise chain. All right, let's see this in action. As you've seen, the three messages appeared with the delay of one second in between. There's a couple more things I want to point out.
[03:33] The executive function is invoked right away when the promise is constructed. It is not called asynchronously. Also, its return value is ignored, so don't bother returning anything from it.
[03:44] Finally, if an error is being thrown within the body of the executive function, the promise that we're creating is going to be rejected. We can verify this by adding a Rejection handler to our promise chain.
[03:56] We're going to log rejected to the console, run our program one more time. As we can see, the promise is rejected right away, and this is it. This is how to use the promise constructor and the executive function to create a new promise.
@Hosarsiph: The promise is only rejected automatically if the executor function throws synchronously. However, that's not the case here. By the time the code within the setTimeout
callback runs, the executor function has been fully executed and exited. Therefore, errors thrown within the setTimeout
callback will not automatically reject the promise.
If there's a risk that your code within the setTimeout
callback might throw an error, you can wrap a try
/catch
statement around it and reject the promise yourself:
const sleep = ms => {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
// ...
throw Error("Some error");
} catch (error) {
reject(error);
}
}, ms);
});
};
Awesome, thanks for the explanation.
I would like to notice the promise chain will break if we throw the error inside the setTimeout. As in the following e.g: https://jsfiddle.net/Hosar/940u8jpx/8/ Instead we should reject the error to keep the chaining. @marius-schulz do you know why this happen ?