Episode Transcript
Transcripts are displayed as originally observed. Some content, including advertisements may have changed.
Use Ctrl + F to search
0:00
Who. Are going to sent a fax
0:02
today. We've got a first of three
0:04
shows on Promises Deep Dive. So I
0:06
was driving home from dropping off my
0:09
kids at school today and I thought
0:11
like. Hung. Out to a showy
0:13
what should we do? you know, and I
0:15
haven't keeping notes on. Just like all of
0:17
these things. That. Surround working
0:19
with promises in javascript I realized
0:22
like man, there's actually quite a
0:24
bit. Too. Or. He
0:26
was promises and or gets acting
0:28
him and flow control and all
0:30
that. So this is going to
0:32
be the next three Mondays are
0:34
going to be all hasty treats
0:36
on deep dive into promises are
0:38
today. We've got sort of an
0:40
introduction understanding how promises work in
0:42
awaiting them in different ways to
0:44
create in listen for a promise,
0:46
resolve, then a second they were
0:48
going to have one on canceling
0:50
promises, helper methods and error handling
0:52
strategies. Her Hattie, Hattie You specifically
0:54
deal with errors. In a
0:56
nice way for your application with
0:58
promises. I'm and than the last
1:01
one we have is getting into
1:03
concurrency queuing, flow control thatch cancelling
1:05
them and difference which is a
1:07
new A P I in in
1:09
the browser so buckle up for
1:11
the next three weeks and we
1:13
are all kinds of. I promise
1:15
you are going to enjoy it.
1:17
I promise you as about to
1:19
make that same joke as yeah
1:22
good or yeah let's see how
1:24
many promise jokes can we make.
1:26
In the next three weeks and if
1:28
you want to see our the errors
1:30
in your application you'll want to check
1:32
out Century ad Century.i owe Forward/syntax you
1:35
can sanjay get two months of free.
1:37
Century is just a really incredible to
1:39
over now only tracking your performance making
1:41
true application has no bugs but even
1:44
just seeing what goes wrong when something
1:46
goes wrong because things go wrong all
1:48
the time when we're coding and you
1:50
don't want a production application out there
1:53
that while you have no visibility into
1:55
in case something. Is blowing up and you
1:57
might not even know it so had already
1:59
century.iowa. again, we've been using
2:01
this tool for a long time and
2:04
it totally rules. All right, I
2:06
think it's a great idea though because you know, I remember
2:09
when I first learned about promises back
2:11
when they weren't in the browser you
2:13
had to use q or bluebird or
2:15
one of those right? Yeah, I
2:17
remember being very confused about why
2:20
they're a big deal. What makes them
2:22
interesting? How is it different than something like
2:25
a callback function? What's the
2:27
deal with promises? So I think this will
2:29
be a really great episode and in this
2:31
episode and specifically, yeah, we're getting
2:33
into promises 101 creating and
2:35
waiting on promises. So I think we can
2:37
start this off with the
2:39
first question.
2:42
What is a promise Wes? A
2:44
promise in JavaScript is an object
2:46
that represents the eventual completion of
2:48
some data and that's different than
2:51
a regular variable or a function
2:53
return in JavaScript because normally
2:55
the result of a promise
2:58
is returned immediately. You get something right
3:00
away but a promise is sort of
3:02
an IOU, a promise
3:04
that eventually at
3:06
some point in the future, I will
3:10
give you some piece of data
3:12
or I'm going to fail which
3:14
is called rejecting. So again, a promise
3:16
is a future agreement
3:19
that some data will be returned
3:21
to you. It's a commitment.
3:23
It's a commitment. Yeah. And
3:28
I thought like let's just kick it off with
3:30
just some common examples of what a promise would
3:32
be. I know most people
3:34
listening sort of understand what a promise
3:36
would be but let's talk about any
3:39
type of data that can be returned from a promise
3:41
which is anything. The most
3:43
common one being you want to take this one?
3:46
Yeah, I think the one that most people have used is
3:48
fetch calls. If you go off
3:50
and you know, there used to be libraries
3:52
and now we have a standardized fetch API.
3:55
If You go off to grab some data from
3:57
anywhere and you're most likely using Fetch. That
4:00
you've ever tried to access that data
4:02
immediately, You'll know that in the returns.
4:04
A promise. It. When. You got
4:06
to do fetch it. It doesn't know how long
4:08
that's going to take it has. I'm gonna go
4:11
get some data. I'll be right back. And.
4:13
Then nice A or it led me. To.
4:16
Wait for that limit out war. we win.
4:18
The data does come back or perhaps perhaps
4:20
you failed to get to the store. Ah,
4:22
then using you know, bring their data back
4:24
and now we can do something with it.
4:26
So he got off to it as trip.
4:28
To. The Store. You've now come back with
4:30
the goodies that you you ordered. Yes,
4:33
And that promises being a
4:36
feature of the language has
4:38
been. An Amazing like
4:40
I know, I'm Most languages have sort
4:43
of the idea of a promise or
4:45
or a way to do this type
4:47
of work by an him. Being able
4:50
to have it as a primitive in
4:52
the language means that you can mix
4:54
and match. Anything that
4:56
returns a promise and you can work with
4:59
them together. This is one thing when there's
5:01
a new thing called the from there have
5:03
been added to promises and it's not really
5:05
like a new thing, but it's It's a
5:08
new A T I that makes working with
5:10
differ. It's a little bit easier in a
5:12
lot of Iraq. Why are they adding all
5:14
the garbage? Why don't you just go in.
5:16
Use this library that already didn't really well
5:19
and often I'm in that camp like nam.
5:21
Maybe we don't need a very opinionated way
5:23
to do this and language bites with with
5:25
promises Being able to. Have a single
5:27
type. Previously. It was like
5:30
Scott said, you have to use Blue
5:32
Bird or Sank or call backs. It
5:34
was very hard to say I want
5:36
me and I work with this database
5:38
adapter and I'm going to be working
5:41
with this A P I that does
5:43
validation or or does a bunch of
5:45
chewing and getting those to work together
5:47
was always kind of frustrating and now
5:49
that we have, we've had them in
5:51
that the browser for many, many years.
5:54
it's much easier. Another example of promises
5:56
would be a database query or an
5:58
insert. command pretty much any database
6:00
ORM that you're using these days if
6:03
your database is not going to solve return
6:06
immediately and even if it
6:09
did that's something called a
6:11
synchronous request or a blocking request and
6:13
what that would do is it would
6:15
actually lock up the rest of your
6:17
application from running. So if you it's
6:19
very hard to actually write code these days where
6:22
you create a blocking circumstance
6:24
but you could if you if
6:27
you did have a blocking database
6:29
right you could run into
6:31
the situation where your server is handling incoming
6:33
requests from the user and if
6:36
you have a insert
6:38
that takes two seconds then all of a sudden you're
6:40
blocking any requests that are coming in
6:42
for two seconds and that's that's sort of a
6:44
bad day. So database queries
6:46
every ORM that you work
6:48
with will return to you a promise and then you can
6:50
sort of just wait for that to successfully
6:53
give you the message say I saved the
6:55
data or resolves to the query of the
6:57
data that's been returned to you. Yeah if
6:59
you if you notice a pattern here we're
7:01
basically anytime something could
7:03
be blocking we use
7:06
a promise so that way it takes something that
7:08
could be blocking and makes it so it does
7:10
not block the execution of other things which is
7:12
one of the reasons why we have to do
7:14
the whole the whole then thing
7:17
with promises that we'll get into. Another
7:19
thing could be requesting the
7:21
user's permissions for things like a webcam
7:24
right the reason why these have to
7:26
be returned as promises
7:28
because you're again you're waiting for
7:30
something to come back from the user's computer
7:32
whether that is prompting them to do a
7:35
permissions acceptance or whatever. And
7:37
then a little wait function is
7:40
example of a promise that you might write yourself
7:42
so you might want to wait for a certain
7:44
number of milliseconds you might want to wait for
7:46
somebody to click on something you
7:49
might want to wait for something to show
7:51
up on the page that's very popular in
7:54
like React testing library where you want
7:56
to stop your code from running you wait
7:58
for something to show up in the page and
8:00
then when that thing is on the page, it will resolve.
8:03
We'll talk about that in just a second and
8:05
you can continue on with your life. So
8:09
promises have two ideas here is
8:11
that when you create a promise,
8:14
you get the option to
8:16
resolve that promise or reject
8:19
that promise. Resolving a promise
8:21
is successfully returning the data
8:24
that that promise has set
8:26
out to go get or
8:28
to go fetch for
8:30
you or to you would resolve after somebody
8:33
clicks a button. That's a successful outcome of
8:35
a promise is called the resolve and
8:37
a negative outcome of a promise
8:40
is called a reject. And often
8:42
you will call reject in your
8:45
promises when you something
8:48
goes awry. Right. That
8:50
that database item didn't save correctly. The
8:52
user did not actually give me access
8:54
to their webcam. Something
8:56
happened inside of this promise where
8:58
there was an error that happened
9:00
because of a different library. Those
9:03
are reject cases. Yes. And
9:05
I don't think this necessarily fits in there,
9:07
but there's also so you
9:10
resolve a rejected promise and those
9:12
things connect very firmly to when
9:15
we're working on promises. We'll talk about this
9:17
in a bit, but that does connect directly
9:19
to the then right. The
9:21
then method is called once a promise
9:23
has been resolved. The catch method has
9:26
gets called when something is rejected and
9:28
then finally gets called no matter what.
9:31
Well, then we'll talk about those more in a second.
9:33
So next step is creating
9:35
promises. So how do you create
9:37
your own promise? But oftentimes we're
9:39
consuming promises, right? We're using a
9:41
dot then we're using a async
9:43
await. We're not necessarily writing
9:46
them, but you can write your own
9:48
promises using new promise
9:50
and you can create a promise. And
9:52
that gives you a callback where
9:54
you can use the resolve or reject
9:57
methods to like Wes mentioned a moment
9:59
ago. either resolve and
10:01
complete the promise or reject and
10:03
fail the promise. Yeah, you are
10:05
often creating your own promises when
10:08
you want to bundle together a
10:10
bunch of functionality and
10:12
often you'll have like nested promises.
10:14
So you might have a promise
10:17
called create user, right? And
10:20
in that create user promise
10:23
or a function that returns a promise, I
10:25
promise I will go and create the user
10:27
and return to you the
10:29
actual user once I'm done. But inside of
10:31
that, you may be doing several things, right?
10:33
You may be doing some sort of validation,
10:35
you might be checking if they have already
10:38
been signed up, you might be hashing their
10:41
password to store in a database, you will be
10:43
actually saving that user to the database,
10:46
you'll be creating timestamps, you'll be maybe
10:48
creating some items that are
10:50
related to that user, setting a bunch
10:52
of permissions and all of those things
10:54
need to happen inside of your promise.
10:56
They can also often chain them together
10:58
and then when you're successfully done, you
11:00
resolve it. If there's an error anywhere
11:02
along the way, you can reject
11:05
that promise and say, this
11:07
is explicitly what has happened. There's
11:10
a new method which I'll talk a bit
11:12
more about in a future episode, this idea
11:14
of deferreds. But promise.withresolvers is
11:16
another way to create a
11:19
promise and that will
11:21
return to you the promise itself
11:23
but also the reject and resolve
11:25
methods at a top level. And
11:28
this can be handy if you want to pass
11:31
the resolver and reject methods to other
11:33
parts of your application rather than doing
11:35
your work inside of the promise itself.
11:38
And then the third way we have
11:40
for creating a promise and this is
11:42
quite honestly the most common way these
11:44
days is you mark a function, a
11:47
sink. And instead of creating
11:49
a new promise and putting all of
11:52
your code inside of a promise callback,
11:54
which does have use cases, you simply
11:56
just Create a function, you mark
11:59
it with this... The key word
12:01
a sink in front of it
12:03
on Media Li that function changes
12:05
from a function that will return
12:07
you data right away turns into
12:09
a function that will return a
12:11
promise. That. Overturned data at some
12:13
point in. The kind of. the cool
12:16
thing about a sink functions is that
12:18
inside of addressing function you can simply
12:20
just return a value. You
12:22
can have other promises and side of
12:24
their and if you return either a
12:27
value or a promise you don't have
12:29
to use the resolves method, you simply
12:31
just return and because the the function
12:34
has been marked as the think it
12:36
will have that. It'll work just
12:38
fine. The same thing with rejecting you
12:41
don't have to explicitly reject. You can
12:43
throw an error which you may be
12:45
used to already in say up. Throw.
12:48
New error. User. Email
12:50
has already been registered. Yeah.
12:53
And here's a small little thing
12:55
for people who find themselves doing
12:57
this: if your function returns a
13:00
promise. Where. You
13:02
don't wanna do is you don't want to
13:04
mark the function as a saying in in
13:06
a way that promise and then return the
13:08
result. You. Just return the
13:10
promise from that function. And
13:13
you returning a promise from the function
13:15
rather than having to create a new
13:17
promise and into it that way So.
13:19
Like. I mentioned within any get into like
13:22
the waiting on a promise bit of this
13:24
as a coma I was, I, oh, I'm
13:26
reading, I had a about that. You
13:28
sometimes do have a think functions that
13:31
return promises and and the use case
13:33
for that is sometimes you want to
13:35
first await something inside of that. And
13:38
then. You may want to
13:40
return the actual promise itself. From that
13:42
functions there's no harm in like sort
13:44
of double wrapping your promises. So if
13:46
you were to have an a sink
13:49
function that returns a promise itself you
13:51
not going to get into any weird
13:53
like nested then set that will be
13:55
an issue for you. Do. You think
13:57
there is a any sort of performance implications there.
14:00
I don't know if there is. I'm just wondering. I don't
14:02
think so. Often I have tweeted
14:04
screenshots of code that I've written and I'll just
14:06
mark a function as a sync and then I'll
14:08
refactor it to return a promise. And
14:11
sometimes there's an unnecessary a
14:14
sync on there, which is why I like the ESLint
14:16
rule. I will be like, you
14:18
didn't await anything inside of this. What are you
14:20
doing? Marking it as a sync. But
14:22
I don't think there is. At
14:25
least I don't know of any
14:27
performance downside to having
14:29
a function marked as a sync if you are
14:32
returning a promise. Word.
14:34
All right. Well, let's talk about waiting on a
14:36
promise, then, because like we mentioned, a promise is,
14:38
you know, the commitment to come back and, you
14:41
know, I'm promising to go to the store and
14:43
get some candy cigarettes. When I come back, I
14:46
better have those candy cigarettes. Do you remember those,
14:48
by the way? Did you ever get those
14:50
in Canada? Yeah, it's pretty wild that
14:52
we just like had cigarettes and they're
14:54
like red on the tips like clearly you're trying
14:57
to make these fake cigarettes. But I said you're
14:59
supposed to like keep them in your mouth. I
15:01
just chomped them up. That's what I did. And
15:03
they're like, I can't I can't do that. All
15:07
right. Well, let's talk about waiting on those
15:09
promises, right? So the main way that a
15:12
lot of people have done it is with
15:14
a dot then method. So instead of using
15:16
a sink await or anything like that, you
15:18
have your promise. Then you say
15:21
you have a function call, right, obviously, and
15:23
then you chain a dot then to the end
15:25
of that dot then has
15:27
a callback. And then that callback has
15:30
the data that's available to you
15:33
if that promises resolved correctly. If
15:36
the premise rejects, you would then need
15:38
to also chain a dot. Catch.
15:41
I don't know why.
15:44
I don't know why I said that, you
15:46
know, apprehensively. You then need to change a
15:48
dot catch in which the error will be
15:50
available in the call that function. And then
15:52
there's also a third one
15:54
that a lot of people don't use, which is
15:57
finally, which this will go no matter what. So
15:59
if you find. yourself duplicating some logic
16:01
maybe like you're waiting for a value
16:03
and then you're setting a state toggle
16:05
based on that value if that state
16:07
toggle is toggled no matter what if
16:09
there's an error or a success
16:11
state you can put that in your
16:14
finally so the finally is gonna run
16:16
no matter what after the catch and
16:18
after the then yeah
16:20
that's that's really handy if you like
16:22
have like a loading state and
16:24
you need to turn the loading
16:27
state off in both cases right
16:29
and after a successful return or
16:32
on error I want to turn the loading state off that
16:34
the finally is super handy for that
16:37
and I quite honestly I don't see it used
16:39
all that often so I think
16:42
I should maybe start using a little bit more
16:44
myself so the
16:47
dot then is a pretty common
16:49
way to do it and then we
16:51
also have the ability to await promises
16:53
so when you're in a function that
16:56
is marked as a sink you
16:58
can sort of pause that function
17:00
from running and once
17:03
the promise resolves itself you can
17:06
continue ongoing so it's a beautiful
17:08
API because you can simply just
17:10
say like const user equals await
17:14
create user whereas the create user function would
17:16
return a promise putting an await in front
17:18
of it will will sort
17:20
of unwrap the promise it will wait for
17:22
the promise to resolve and give you the
17:25
actual data at the end of the day
17:27
await also is used for generator functions but
17:29
we're not getting into that in the promise
17:31
episode so I in
17:33
most cases I would say most people
17:35
use the async
17:37
await API simply because it reads
17:39
a lot nicer we'll
17:41
talk a little bit more about error handling and how
17:43
to mix and match them there are use
17:45
cases where you still want to use the dot then chaining
17:49
is a really nice one instead of just doing
17:51
await await await some people like to chain then
17:53
then then onto one another
17:56
the other one being that sometimes
17:58
you want to listen for
18:00
when something is resolved, but keep
18:02
the function going while you're
18:04
waiting for it. So a very common use
18:07
case that I've seen
18:09
is you want to go off
18:11
and fetch something. And then the next
18:13
line below that, you wanna set up like an
18:15
event handler for when somebody clicks
18:18
something or when a specific event happens. If
18:20
you were to await that fetch request, the
18:22
event handler would never run until, because
18:25
you're essentially pausing the use case. Same thing
18:27
with streams as well. That's a pretty common
18:30
use case where, all right, I'm
18:32
gonna set up this stream and
18:35
I'm gonna resolve once it's actually finished. So
18:38
what do you use, Scott, in most cases? Do
18:40
you default to sync await? Yeah,
18:42
my default is, it is
18:45
funny, because sometimes it feels haphazard in which I'll
18:47
be like, oh, I'm not inside of an async
18:50
function. I don't feel like making this function
18:52
async. So I'll just throw a dot then
18:54
on there. To
18:56
me, it depends on what I have to do with that
18:58
data. The thing that's always bugged me
19:01
about the then methods is that
19:03
you're now going another
19:05
layer deep, right? If
19:07
you wanna access that data outside of the premise, you
19:09
have to create a variable and
19:11
pass it in and worry about the
19:14
default values before and after the premise
19:16
return. So almost always I'm using await
19:18
just because it reads more like how
19:20
I would expect it to work and
19:22
then I can access the values where
19:24
I want to access them. All
19:27
right, wait for the value, it's there. Now
19:29
I can do something with it. But there
19:31
certainly are times where I am using a
19:33
catch or a dot then as well. I do
19:35
use a dot catch even
19:37
on await instead of doing a try catch now.
19:41
Yeah, that's something we have coming up in
19:43
the next one, which is error handling strategies
19:45
of like mix and matching. I
19:47
personally do that as well as I await, but
19:50
I use a dot catch to catch
19:52
the error in most cases. Chaining
19:54
the dot thens onto each other. And I should
19:56
say the way that this works is if you
19:59
have a dot catch, Then if
20:01
you return another promise from that dot
20:03
then you can chain them Indefinitely
20:06
and put a single dot catch at
20:08
the end of it any errors
20:10
that happen along the chain Where that
20:12
becomes an issue is then you have your a weird scope?
20:15
Which is hard and it's also really hard to like
20:17
pass data between the two of them So
20:19
if you have one promise
20:21
that fetches the weather and then another promise
20:24
that saves the weather to the database You
20:27
find yourself having to modify Functions
20:30
so that they'll accept the incoming
20:33
weather data and then that's
20:35
really frustrating because Now
20:37
if you want to comment one of them out Then you
20:40
have to change the signatures again, or
20:42
you create like a variable that's outside the scope
20:44
of the dot then and you sort Of update
20:46
it that's annoying because now you have like an
20:48
undefined variable for a short amount of time and
20:50
you have type script That's a bit tricky. So
20:53
yeah, I like I like the
20:55
the I I
20:58
Think await much better. The only time like
21:00
I'll mix and match them is often with
21:02
the dot fetch I'll
21:04
have the await whatever and if you
21:06
have to get Jason back, you know
21:08
It's Jason the fetch has like a
21:10
double promise thing, which we'll explain in
21:12
the in the next episode Sometimes
21:14
I'll just chain a little dot then on top of
21:16
it But
21:19
I think that's that's all we have for
21:21
the first episode again That was pretty high
21:23
level of explaining promises in the next episode.
21:25
We're going to get into Canceling
21:28
promises a boarding promises
21:30
some of the promise helpers, which
21:33
is all all settled Finally any
21:35
and race as well
21:37
as five different ways to handle
21:40
error handling strategies Sick.
21:43
I look forward to your promise of
21:45
future episode promise. It will be good.
21:47
Please. I can't wait You
Podchaser is the ultimate destination for podcast data, search, and discovery. Learn More