Promises in JavaScript

Pro Members Only

This lesson is available if you have an active subscription.

Alternatively, some member might be able to gift it to you.

If you already have a subscription, you can sign in.

Professional Modern JavaScript Lessons

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36

Promises in JavaScript

Subscription Required

You must have an active subscription to access this content.
If you already have a subscription, you can sign in.

Basics

const promise = new Promise((resolve, reject) => {
// do some async work
// resolve OR reject
})
.then((value) => { console.log('Fulfilled', value) })
.catch((error) => { console.log('Rejected', error) })
.finally(() => { console.log('Settled') });

Static Resolve and Reject

function resolve(value) {
return new Promise(res => res(value));
}
function reject(error) {
return new Promise((_, rej) => rej(error));
}

resolve('success')
.then(v => console.log(v));
reject(new Error('fail'))
.catch(e => console.log(e.message));

Promise.resolve('success')
.then(v => console.log(v));
Promise.reject(new Error('fail'))
.catch(e => console.log(e.message));

Promise Chain

Promise.resolve(123)
.then((v) => {
console.log(v); // 123
return 456;
})
.then((v) => {
console.log(v); // 456
return Promise.resolve(789);
})
.then((v) => {
console.log(v); // 789
});

Fulfilled dependency

function resolved(value) {
return new Promise(resolve => resolve(value));
}
const delayFulfill = () => new Promise(
res => setTimeout(() => res('fulfilled'), 1000)
);
const delayReject = () => new Promise(
(_, rej) => setTimeout(() => rej(new Error('rejected')), 1000)
);
const alpha = resolved(delayFulfill());
const beta = resolved(delayReject());
alpha
.then(v => console.log('alpha then', v))
.catch(e => console.log('alpha catch', e.message));
beta
.then(v => console.log('beta then', v))
.catch(e => console.log('beta catch', e.message));

Fixing Callback Hell

Hell:

/**
* Call cb three times in sequence,
* each time after 1s delay
*/
function run(cb) {
setTimeout(() => {
cb();
setTimeout(() => {
cb();
setTimeout(() => {
cb();
}, 1000);
}, 1000);
}, 1000);
}
run(() => console.log('hi'));

Heaven:

const wait = (ms) => new Promise(
(res) => setTimeout(res, ms)
);

function run(cb) {
wait(1000)
.then(cb)
.then(() => wait(1000))
.then(cb)
.then(() => wait(1000))
.then(cb);
}

run(() => console.log('hello'));

Error Propagation

new Promise(res => {
res('hi');
})
.then(v => {
console.log('then', v);
return Promise.reject(new Error('fail'));
})
.then(v => {
console.log('then', v);
})
.catch(e => {
console.log('catch', e.message);
});
javascript
typescript
react
playwright

Enjoy free content straight from your inbox 💌

No spam, unsubscribe at any time.

Transcript

00:00

Before we can really take advantage of the wonderful modern features of async weight, we need to get a firm understanding of the built-in JavaScript promise class. We can create a promise in JavaScript by using the built-in promise constructor. The promise constructor takes an executor function as an argument and then invokes that with two parameters. The first one is resolve and the second one is reject. And these two arguments are what will determine the eventual fate of the promise. Within the executor function, we can do some async work and then eventually invoke either resolve order, reject the resolve function can be used to provide a value which will fulfill

00:35

the promise with that value. And the reject function can be used to provide an error which will result in the promise being rejected. In either case, whether the promise is fulfilled or rejected, it is considered settled and we can actually subscribe to that event as well by using the final method. Right now we are not in working resolve or reject, and this will put the promise into a pending state and none of the then catch. And finally, method callbacks will get invoked. Let's change that by first doing some async work and then settling the promise. We don't have to do asynchronous work within the promise constructor,

01:09

but really the ability to do so is the reason why we want to use the promise. Here we are setting a timeout of a one second and then resolving the promise with the value of the string arrived. Once the resolve gets in booked, the promise will be considered fulfilled, which is a subset of the category called settled, and we will see fulfilled with the value that we provided along with the string settled on the console. The unhealthy fate of a promise is that it might get rejected and we should always reject with an error object. So we invoke the reject method, passing an error object with a nice descriptive string,

01:42

and this will result in the promise getting rejected with the error, which in turn will invoke the catch handler. And since we are using an error object, we get a nice stack trace for the origin of the error. And just like fulfilled, rejected is a final state of the promise, which means that the finally callback will also execute and we see settled on the console. So in short, promise is simply an object that is used to manage async tasks that start off as pending and then settled with either a status of fulfilled or rejected. Promises come with simple static methods that allow you to create promises which

02:17

immediately resolve or reject the promise with a given value. For example, we can easily create a function ourselves called resolve. That takes a value, then returns a promise, which we immediately resolve to that value. Similarly, we can create a function called reject that takes an error and then returns a promise which may immediately reject with that error. So if we create a promise with the resolve callback, it'll immediately get fulfilled, which means that the then callback will get called. And similarly, if we create a promise with reject, it'll immediately get rejected, which means that the catch handler will get called.

02:51

And having these utility functions can really help understand some of the behaviors of promises, but fortunately we don't have to create them that often As JavaScript becomes a built in with static methods promise or resolve and promise or reject that offer very similar features and even do a few performance optimizations. As an example, if you give promise to promise dot resolve, it just gives it back to you. It doesn't wrap it up any further. Our versions of these functions as well as the promise static versions of these functions, we log exactly the same thing, which is success and fail, and we can verify that in the program output.

03:25

A key feature of Taki promises is how the promise then method chains together. It even allows transparent unwrapping of promises, which means that we don't have to untangle a mess of nested then calls. We start off our chain with a simple promise which we resolve to the value of 1, 2, 3, which means that the then callback should be called with 1, 2, 3 each. Then callback actually creates a new promise and that promise will in turn resolve with whatever value we return from our then call. So as an example, if we return the value 4, 5, 6, the next then callback, we'll get the value of 4, 5, 6 because that is what this new promise will

04:01

resolve to. Now again, this then is actually creating a new promise and whatever value will return from here will determine the fate of that promise. We can actually return a promise from our then callback and that will actually tie the fates of our return promise and the promise created by then to be the one and the same. The promise we are returning is going to resolve to 7, 8, 9, and the promise created by then is going to resolve to the same value, which is what we will see in the next then callback. Let's run this code and you can see that it works as expected. The first time you see this collapsing of promises, it can look a bit weird, but this is a fundamental part of the power of promises.

04:37

Notice that we've been using the term fulfilled a few times instead of resolved, and the reason is that a promise can be resolved to another promise, at which point it's fate becomes dependent on the other promise. If the other promise gets fulfilled, our promise gets fulfilled. If the other promise is rejected, our promise is rejected. We create this utility function called resolved that takes a value and then returns a promise that is clearly resolved to that value. We have another utility function that returns a promise that just chills around for one second and then becomes fulfilled. And very similar to this, we have a til which returns a promise,

05:12

which again just chills around for one second and then becomes rejected. Let's create two promises, alpha and beta. And both of these promises are clearly resolved because the resolve method has been invoked as we have been seeing when we invoke resolve with the value, that is not a promise. The promise immediately moves into the fulfilled state and that then callbacks get called. However, when we resolve a promise to another promise as we are doing over here, then the fate of the promise becomes dependent upon the past in promise. So both alpha and beta are clearly in the resolved state,

05:45

but they haven't settled yet as their faiths are dependent upon the past and promises. And eventually once their fate is decided, alpha will get fulfilled and P will get projected and we can verify that by attaching then and cash to both alpha and beta and logging off the results. And as you can see, AFA gets fulfilled and beta gets rejected. So to recap with the non-pro value, a resolved results in an immediate fulfilled, but with the promise value, the fate is dependent upon the past and promise even without a single weight. Promises by themselves help clean up the callback. Hell also called the callback tower of tomb.

06:18

And the critical feature that offers this is the fact that the promise then function automatically waits for any past promise to settle before continuing. Consider the simple task of creating a run function that takes a callback and then simply calling the callback three times each time after a delay of one second with the knowledge that we already have, it's quite easy to do with the set timeout. We set up a timeout, invoke the callback and set the new timeout, invoke the callback, and then set the final timeout and invoke the callback. And of course, all of these timeouts are going to be for one second and we can prove that it functions the way it should by giving it a simple callback that logs high.

06:55

And we see the three high calls each time after one second, and I think you can see this sideways tower of doom that is forming because of this nested callback hell. So let's take a look at how we can achieve the same thing more cleanly with promises. Since we have a requirement to wait a particular amount of time, we'll just create this utility function that takes a number of milliseconds and then returns a promise which we will eventually resolve after the desired number of milliseconds Using set timeout, let's recreate a run function that takes the callback as an input and we will kick things off by creating the promise that will wait for one second before

07:29

resolving, and then we will invoke the callback and then we can just return a new promise that will again wait for one second and then invoke the callback and finally repeat the process one more time. The automatic promise unwrapping and chaining just makes this code much neater than the set timeout version. Let's demonstrate this run function by giving it a callback that logs hello to the console and if we run it, we see hello after every second for three times. Perhaps the most amazing feature of promises is its graceful error handling and how it cascades through the promise chain.

08:02

Consider the simple promise chain where we start off with a promise that resolves too high and then we log out this value and then return a new promise which will resolve to hello, and then we log out that value and then eventually add a catch handler that will log the message of any error that it might receive. Of course, there are no errors in the code right now, so if we execute it, we see then hi, then hello, and we do not see any catch. It should come as no surprise that if we throw an error in the final then call, it'll result in a promise rejection and our catch handler will get called and we can verify that from the console.

08:36

But what might actually surprise you is that this catch handler is actually handling the error that can happen anywhere within this promise chain. As an example, if an error happens in the promise constructor that will result in that promise getting rejected, the error will cascade all the way to the catch callback and all the intermediate promises will also fail. Similarly, If an error happens in the first 10 callback, the remaining promises after that will get rejected and we will jump straight to the catch. As we can see in the output here, we are the ones that are throwing an explicit error, but then error can be thrown by the JavaScript on time as well. As an example, if you try to use a variable that hasn't been defined called magic,

09:12

then of course we are going to get a reference error and that error cascades all the way to the catch. Additionally, at any point, if it return a promise, then the fate of the remaining chain becomes dependent upon that promise. For example, here we are returning a promise that will reject. So of course, just like any other error, the remaining chain will reject and we will jump straight to the catch as we can see in the program output. This crystal error handling cascade means that we don't have to later our code with validation. And this is also what makes it possible to easily map promises to the JavaScript. Try-catch with Async await in modern JavaScript, understanding the concept of promise fates, how the promise then chain works,

09:49

and how the catch cascades is sufficient to start using async weight, which really takes the utility of promises to the next level. As always, thank you for joining me and I promise to see you in the next one.

Professional Modern JavaScript

Professional Modern JavaScript

1.Course Intro
free
⏱️ 1:13
2.Setup & Tooling
free
⏱️ 3:32
3.Debugger Statements and Breakpoints
free
⏱️ 2:17
4.Primitive Data Types and Values
free
⏱️ 3:06
5.JavaScript Variables - let and const
free
⏱️ 4:50
6.Comments in JavaScript
free
⏱️ 2:55
7.JavaScript Identifer Naming
free
⏱️ 2:52
8.Using TypeScript
free
⏱️ 4:26
9.JavaScript String Masterclass
free
⏱️ 9:29
10.JavaScript Boolean Type
⏱️ 6:45
11.Missing Guide to JavaScript Numbers
⏱️ 15:28
12.JavaScript Objects Demystified
⏱️ 13:33
13.Functions in JavaScript
⏱️ 20:25
14.JavaScript Arrays Masterclass
⏱️ 22:31
15.JavaScript If Else Statements and Best Practices
⏱️ 6:13
16.JavaScript Conditional Expressions
⏱️ 8:38
17.JavaScript Loose vs Strict Equality
⏱️ 4:02
18.Truthy vs Falsy in JavaScript
⏱️ 3:44
19.Concept of JavaScript Nullish and Unification
⏱️ 5:51
20.JavaScript Classes - Object Oriented Programming
⏱️ 10:30
21.JavaScript Error Handling and Exceptions
⏱️ 13:21
22.JavaScript Nullish Operators
⏱️ 5:48
23.JavaScript Switch Statement Masterclass
⏱️ 8:07
24.JavaScript For Loop Iteration Simplified
⏱️ 10:59
25.JSON Masterclass
⏱️ 7:59
26.JavaScript While and Do While Loops
⏱️ 2:52
27.JavaScript Date and Time Simplified
⏱️ 13:16
28.this in JavaScript
⏱️ 12:04
29.JavaScript Tagged Templates Masterclass
⏱️ 5:48
30.Promises in JavaScript
⏱️ 10:01
31.JavaScript Async Await Masterclass
⏱️ 9:00
32.JavaScript Symbols Demystified
⏱️ 7:25
33.JavaScript Iterators and Iterables
⏱️ 8:50
34.JavaScript Generators Simplified
⏱️ 9:17
35.JavaScript Prototype - The Secret Guide
⏱️ 11:21
36.JavaScript Set Builtin Data Structure
⏱️ 9:52
37.JavaScript Map Builtin - HashMap Magic
⏱️ 10:38
38.JavaScript Deferred Promise Pattern - withResolvers
⏱️ 3:35
39.Cloning and Deep Copying in JavaScript
⏱️ 3:14
40.JavaScript Async Await Sequencing and Execution Masterclass
⏱️ 10:31
41.JavaScript Memory Management Masterclass
⏱️ 5:26
42.JavaScript WeakMap Demystified
⏱️ 8:58
43.JavaScript bigint Masterclass
⏱️ 5:35
44.JavaScript WeakSet Explained with Examples
⏱️ 7:47
45.JavaScript Regular Expressions Masterclass
⏱️ 17:54
46.JavaScript Weak References Demystified
⏱️ 5:29
47.JavaScript Memory Leaks Demonstrations and Fixes
⏱️ 6:01
48.Semicolon Free Coding in JavaScript
⏱️ 3:46
49.JavaScript Modules Masterclass
⏱️ 11:36