Episode Transcript
Transcripts are displayed as originally observed. Some content, including advertisements may have changed.
Use Ctrl + F to search
0:00
Oh. I come to syntax
0:02
in this episode work to be taking
0:04
a part to to our series on
0:06
Promises and in this video or to
0:08
be talking about error handling we're going
0:10
to be talking about a boarding a
0:13
problem as helper methods and more. So
0:15
ah yeah we're going to continue our
0:17
our talk on promises and after this
0:19
when I think you'll never a great
0:21
idea about a little bit more in
0:23
terms of how to use them beyond
0:25
just the basic. So many not got
0:28
dramas. I. Promise you're going to
0:30
have a good idea where? Okay. Well
0:34
I promise you my name is Scott
0:36
to Lynskey and I'm from Denver with
0:38
me. As always is West passwords up
0:40
wears a not too much. I promise
0:43
that if you have issues with their
0:45
promises you're going to want to check
0:47
out Century cause center is gonna tell
0:49
you when your promises are thrown. Maybe
0:51
when they're the have an on caught
0:54
reject in one a your promises that
0:56
you weren't expecting can tell you I
0:58
myself am. Node used to have this thing called.
1:01
Know. Use the catchier uncap promises And
1:03
they warned for years that they're going
1:05
to turn it off. And. I
1:07
said. Yeah. Yeah to him.
1:09
One day masters my server crashed and
1:11
whenever my server crashes I get a
1:13
little century alert and I get an
1:15
email about it and I logged in.
1:18
I thought oh why do my server
1:20
crash and I looked at the center
1:22
air it was a fetch quest than
1:24
I had not been are no it
1:26
wasn't effect yet whether fetch requests but
1:28
it was a post so as posting
1:31
some data to a third party service
1:33
that service had an outage. And.
1:36
Because it was on handled. I.
1:39
Didn't catch their. Part. My
1:41
entire server crashed which is unreal
1:43
that I could crash entire server
1:45
just with the a single fetch
1:47
requests. But that happens and center
1:49
is able to am tell me
1:52
exactly what happened. I fix it
1:54
and like three minutes. So check
1:56
it out, Century.i'll check it out.
1:59
dick Well, let's get
2:01
into the first section of this
2:03
episode. We're going to be talking
2:06
about canceling promises. So you
2:08
have a promise that goes off and
2:10
like, I'm sending, or you're
2:13
sending me to the store, right? The
2:15
promise is that I'll return with the stuff. At
2:18
any given point, you can call me
2:20
up and say, hey, Scott, come
2:22
back. Yeah. Cut it out.
2:25
Stop doing what you're doing. I found the
2:27
cheese in the fridge. We don't need any
2:29
more cheese. Or it's a good way. You
2:32
can reject a promise at any time. So
2:35
that is entirely up to you. And
2:38
you can return with
2:40
the resolve or reject methods at any
2:43
time as well. You
2:45
basically have control over the
2:47
full process throughout which you're
2:49
working with your promise. Yeah.
2:52
Inside of a promise, you can, like
2:54
we said in the last episode, you get your
2:57
resolve, you get your reject methods and you can
2:59
do whatever you want with those. And
3:01
often what that includes is
3:03
you have some logic inside of your promise
3:05
that says, given
3:07
these use cases, maybe after
3:10
I've tried clicking the button
3:12
six times and it doesn't work, then
3:14
reject. Or after pretty common is you
3:16
want to put a five second timeout
3:19
on a promise. Say after
3:22
five seconds, if the thing doesn't come back
3:24
with data or after five seconds, if the
3:26
user hasn't clicked this button, then we need
3:28
to do something in order
3:30
to show that you'll catch the reject
3:32
in that case. So that's
3:34
an example of when you would want to put
3:37
the logic inside of a promise. Also
3:39
we have promise.withResolvers. Again,
3:42
we'll talk about them a little bit more
3:44
in the next episode. It's called deferred. But
3:47
essentially promise.withResolvers will give you the promise,
3:49
but it will also give you the
3:52
resolve and the reject methods outside of
3:54
the promise instead of inside of the
3:56
promise callback. And that can be
3:58
handy if you want. You want to pass
4:01
those pretty much succeed and
4:03
cancel functions if
4:05
you want to pass them to something else. For
4:07
example, I have buttons on
4:09
an example somewhere where if
4:12
you press the done button, that
4:14
is resolved. But if you push the cancel button,
4:16
that is a reject. Often you can just wire
4:19
those up directly to an Ad Event listener and
4:22
you're up and running. So that's another way
4:24
you can cancel them. And then also in
4:26
Fetchland, we have this
4:28
idea called an Abort Controller. And
4:31
you create an Abort Controller
4:34
and that Abort Controller itself
4:36
has what's called a signal. You pass
4:38
that signal to a fetch request and
4:41
then you're able to control that fetch
4:43
request from wherever you have access to
4:45
the Abort Controller method. It's a little
4:47
bit more complex and simply just rejecting
4:50
because you do want to also cancel
4:52
the network request and that will take
4:54
care of all of that stuff for
4:56
you, as well as there's
4:58
a built-in signal for simply just doing a timeout.
5:01
Because if you want to set the timeout of
5:03
a fetch function, you don't
5:05
have to wrap it or anything. You simply
5:07
just pass the signal of abort signal.timeout 500
5:10
milliseconds and then nothing will reject if
5:12
there's no response back after five seconds.
5:16
Why would you reach for an abort signal? Because
5:18
that's not something I feel like I've ever had
5:20
to do. A good
5:22
example would be if you have
5:24
a type of head that is sending
5:26
off fetch requests. So you'll have a
5:29
search box, you start typing in cool and
5:31
then you stop for a second and it goes, I'm
5:34
gonna start searching for cool. So it sends a
5:36
fetch request off to your API and
5:38
as that fetch request is in flight, you
5:41
just type ify, F-I. Okay,
5:44
now you've sent off a second request
5:47
to the server for coolify.
5:49
Now you have two fetch requests
5:51
in flight and it is not
5:53
guaranteed that they will come back
5:55
in order That you've done
5:57
it. And Often developers don't realize this. Working
6:00
at a local database and on local
6:02
house and there's no latency at all
6:04
but you get into real world conditions
6:06
your database somewhere different the drax a
6:08
user there could be real world thing
6:10
so as you are typing if you
6:12
are firing off a second fetch requests
6:14
you need to make sure that you
6:16
up or any other. Requests. That
6:18
are currently still in flight, so that's where
6:20
you'd want to use an abort signal. Thank.
6:24
You thank you for that? Yes,
6:26
yeah. Fluid set about some of
6:28
these additional helpers for promises. You
6:31
may have seen some of these
6:33
like promise, dad. All words promised
6:36
at all except an array of
6:38
promises And is where it will
6:40
do. is it returns. Why
6:43
should the promise itself? Fulfills.
6:46
Once. The. Promises themselves
6:48
complete and A usually gives
6:50
you essentially an array of
6:52
the values that come back
6:54
from those promises. Now I
6:57
am curious west as I
6:59
know you know more about
7:01
this than I do. You
7:03
promise.all settled. What is the
7:05
difference between promise? All in
7:07
promise? All settled. So.
7:09
All was initially rolled out when
7:11
we got promises. And.
7:14
The downside to that is if one of
7:16
those values rejects know whole thing is is
7:18
over south from said I'll take that. I
7:20
like you said an array of promises at
7:23
wrap them up into one mega promise me
7:25
up and it waits for all of the
7:27
promises to be done. And if one of
7:29
I'm takes one second in one of them
7:32
takes ten seconds you're going to be way
7:34
the full ten seconds before you get all
7:36
of the dead rights. But if one of
7:38
those were to reject. You. Might
7:41
have to successful promises, but there's
7:43
no way to get that data
7:45
anymore because. It's is
7:47
rejected and immediately you go straight to
7:49
the cats. When you're you're chaining right?
7:51
known as kind of a pain. If
7:53
you do care about the successful ones
7:55
have a not out one that was
7:57
was failed rights like for example of
7:59
your. Uploading seven photos.
8:02
Are you might want to do
8:04
Promise.all. And upload all seven
8:06
concurrently on the same time. For.
8:09
Ref: one of them doesn't upload because
8:11
it's too large or a sarong. files
8:13
I personally like that's the other six
8:15
that may have been uploaded correctly or
8:18
are are still in process. They're.
8:20
All aboard at right and you're era.
8:22
You're outta luck. Know all Settled will
8:24
returns you an array of the results
8:27
regardless of if they were all successful
8:29
or not. Will give you an array
8:31
of to tax the data. Each item
8:33
in the array will be and will
8:36
have a status. Which is
8:38
fulfill the rejected which is. A
8:40
little annoyed to me that that's is called for.
8:43
Still the rejected sit in that say. Resolve.
8:45
Their rejected. Maybe. Knots
8:47
and then on successful ones. You'll get
8:49
a value property which has the data
8:51
that you're lucky for and then the
8:53
aired out ones. You'll get a reason
8:55
property which will have. Whatever.
8:57
is passed to the rejected method that
9:00
you have their so I would say.
9:02
I'm in. I'm in Unless you
9:04
are one Abort Everything. Abandoned.
9:06
All ship as soon as one of them
9:09
breaks. You probably want all settled in modern
9:11
is now and then. Promise that finally you
9:13
mention this last show of it being really
9:16
handy as if you want to do something
9:18
after it resolves or rejects like turn off
9:20
a loader. Then. You can
9:22
use finally. And. That or run
9:24
in either case. Now. There.
9:27
Is also I can confidently say I've
9:29
never used either of these. yeah I'm
9:31
I'm curious if you ever have he
9:33
he their this promise that any and
9:35
promise that race you want to guess
9:37
what those are more lascivious them yourself
9:39
and you have them Mrs I you
9:41
know it just looking at these I
9:43
would say. That. Any
9:46
resolves once any of the
9:48
promises have resolved. But.
9:54
Maybe Okay Here's when I'm in a guess.
9:56
This is this is just totally off the
9:58
wall guess for me. I'm gonna say
10:01
they both. Return.
10:03
Once the first promise resolves I
10:05
would imagine that maybe any also
10:07
resolve the other promises were race
10:09
stops trying to resolve the other
10:12
promises as close so they both
10:14
you're right in that they both
10:16
will resolve as soon as the
10:18
first promise is is uploaded. So
10:21
maybe have two different eighty eyes
10:23
and you're sending data to to
10:25
because you you want to have
10:27
like double back ups rights and
10:29
you only care. That.
10:32
Something has been sent to one
10:34
of them frames and both of
10:36
those will resolve as soon as
10:38
the first. One is
10:41
finished. The difference being
10:43
that. Promise. Dot
10:45
race or return the first
10:47
settled value. And
10:49
at a settled is a
10:52
reject or resolve were as
10:54
promised that any will return
10:56
the first fulfilled value. So.
10:59
Any his success only
11:01
race will return the
11:03
rejected or. For. Know can
11:05
resolve value sellers to and again
11:07
and I know like in in
11:09
what case or you're firing off.
11:12
Multiple. Promises? Maybe like. If
11:14
you had a promise that was
11:16
waiting for a click on multiple
11:18
buttons noom see you might have
11:20
like six promises that are waiting
11:22
for clicks on six different buttons.
11:25
You my only care. As
11:27
soon as somebody clicks one of those
11:29
buttons, and as soon as somebody close
11:31
one of those buttons, then you want
11:33
to continue on with the rest. So.
11:36
I put although like just you could
11:38
pass and multiple selectors to some like
11:40
that Us while I know that's a
11:42
contrived example that are China China twist
11:44
into work in here. Ah, if you're
11:47
out there and you're missing the this
11:49
insane guys I have the perfect use
11:51
case for this. Hit us up
11:53
on you tube! drop a comment in the
11:55
video below this video i want a
11:58
hero people are using race for specifically
12:00
because I have used any but I've
12:02
never used race before and either way
12:04
these aren't things I need to reach
12:06
for very often. Let's
12:08
talk about error handling within promises.
12:11
Now typically if you're chaining methods
12:13
on a promise you can always
12:15
add a .catch method that
12:17
takes a callback with the error that gets
12:19
returned there. So you've seen that where it
12:22
has a callback with an E or an
12:24
error then you can console
12:26
log the error you can throw it
12:28
to sentry you can do all kinds
12:31
of stuff with it to ensure that
12:33
your UI is responding accordingly to
12:35
whatever is happening with that .catch.
12:38
Now you can also use a
12:40
try catch statement to wrap your
12:42
await inside of when
12:44
you're going to await a promise. However
12:47
one thing that I learned from Wes
12:49
a little while ago is that you can mix
12:52
these approaches where you can
12:54
await a variable result but
12:56
still chain a .catch onto
12:58
that bad boy so that way you don't have
13:00
to wrap the whole thing inside of
13:02
a try catch. I don't know
13:04
why but try catch feels so obnoxious
13:06
to me it pop it like it and then
13:09
re-indents my code all by one it feels like
13:11
it takes up a lot of space that's
13:13
one of those ones where it's like I
13:15
will use the .catch method and I will
13:17
use await to get the
13:19
value out of a promise typically. One
13:23
kind of way that I've been writing a
13:25
lot of my promises lately is this idea
13:28
of writing a wrapper function around
13:30
your promises that will
13:32
internally run a try
13:34
catch and will return
13:37
from that function a
13:39
what's called a tuple and
13:41
a tuple is like an array
13:43
that has a known length and a
13:46
known type and back
13:48
in the day in Express.js
13:50
and No.js land the way that it
13:53
worked is your callbacks would often give
13:55
you the error and the data and
13:57
you would either have the error or
13:59
the data. data and that was really nice
14:01
because you could first check if there was an
14:03
error and if there's not
14:05
you can continue on with the actual
14:07
data and that's a little bit
14:09
tricky because you could
14:12
do try catch and then you
14:14
got to update variables outside of the scope
14:16
that's kind of annoying. You can use the
14:18
away and dot catch but if
14:20
you want the actual error on the next line
14:22
then again it's out of scope you don't have
14:24
access to it you gotta do some weird variable
14:27
things. So with this
14:29
idea of I call it collect
14:32
in my types of course we create a function
14:34
called collect and learn how to like use generics
14:36
to type something that is so abstract
14:39
but there's a really popular library out there
14:42
called await to JS and
14:44
this will just give you a function
14:46
that you can wrap your promises in and then it
14:48
will return to you an array
14:50
first item being the actual
14:52
error second item being the
14:55
actual data and that's really nice if you
14:57
need to first deal with an error before
15:00
you go on with
15:02
the rest of your thing most commonly being like
15:05
you try to save an item to a database you
15:08
get the result back you want to
15:10
first check hmm was there any errors saving that
15:12
item to the database if so
15:14
then render an error page
15:16
if not continue on with the rest of the
15:19
page maybe render out the user page. So
15:21
I've been a big fan of this approach. I
15:24
have two statements on this one. Yeah
15:26
we should take your collect and turn
15:28
it into a library and we can
15:30
call it collect call. That's good. That's
15:32
a good joke. Oh
15:34
that's great. Thank you. And
15:37
second I you
15:40
know just even saying this makes
15:42
me wonder why you know
15:44
dot catch or even
15:47
like it feels like the error should
15:49
be the first in my logical brain
15:52
when you're doing a promise like oh
15:54
if this fails take care of the
15:56
failure first then if it
15:58
didn't fail we know it succeeds like. Logically the
16:00
order of that makes way
16:02
too much sense I've never used a wait
16:04
to JS or any of this stuff before
16:07
but I like the way it reads when
16:09
you look at the code Yeah,
16:11
I was I always was a big fan
16:13
of this approach. I think it was I'm
16:18
trying to wonder like who popularized this in
16:20
node.js land. I think some of the even
16:22
the node API's that are callback based Were
16:25
like that it's been so long since
16:28
I've worked on it But yeah, it was always
16:30
give you the error first then the data and
16:32
that forces you to think okay Handle
16:34
the bad case first and then you have your
16:36
your happy path gotta have your happy
16:39
path. So Yeah, that's I
16:41
have a little YouTube video. I'll link up here
16:44
detailing the different a
16:46
sink away error handling strategies because Not
16:50
one is better than the other I use all of
16:52
them. Sometimes I try catch sometimes the catch is good
16:55
Often a mix and match is really good. And
16:57
then if I'm doing it specifically when
16:59
I do a lot of like node.js Database
17:01
work I'll reach for the collect
17:04
or a wait to JS Implementation.
17:07
Yeah. Yeah, it
17:09
is interesting because you like you said like
17:12
you do it different ways to me It's
17:14
one of those as a
17:16
feeling things because you can typically write most
17:18
of the stuff you're gonna do with any
17:20
of these approaches and I
17:22
think over time you just kind of get a feeling
17:25
for which way you like to do what and then
17:27
that's typically How it
17:29
feels for me. I have a
17:31
really good promise dot race example So
17:33
often when I don't know how people
17:36
use API's I'll just go
17:38
on get up search and search for that
17:40
API and yeah I do that Tim scroll
17:42
through 15 20 different code
17:44
examples Like what are people actually using this for
17:46
and you know what? This is such a good
17:48
example of what is used for is that if
17:52
you want to add a timeout? To
17:54
something that has a promise, but that
17:57
promise Doesn't have
17:59
the option to pass it in like you're
18:01
using somebody else's API. They don't allow
18:04
you to pass in a timeout, right?
18:06
Or you have your own promise based function, but
18:09
then you have to re implement
18:11
the timeout functionality in every function.
18:14
And you know, you have to add a timer
18:16
to it. And that's annoying. That's one of the
18:18
nice things about fetch where it's built in, but
18:20
not everything is a fetch. So promise.race, what
18:24
you can do is you can say, uh, const
18:26
result equals await promise.race,
18:29
pass it your original promise function and pass
18:33
it a like a timeout function that
18:35
will throw. And then
18:37
that's beautiful because it makes sense either, or,
18:39
or not even throw. You could just resolve
18:42
after one second. And then
18:44
if, if the result is empty, then it timed
18:46
out. And if the result is there, then, then
18:48
it worked. Love that. Hey,
18:50
love that. Yeah. I
18:53
learned a thing or two. Uh, last thing
18:55
we have here is the capital P promise
18:58
in JavaScript has two static methods
19:00
on it. So dot reject and
19:02
dot resolve. And I've always wondered like,
19:05
why are those there? You know, like
19:08
what are those for? And I realized
19:11
I had used them a couple of times is if
19:13
you are returning values from
19:15
a function that may not be a promise, but
19:18
you want to still maintain the whole promise API
19:21
because everything else you're
19:23
working with is a promise. So for example, you
19:26
might have a cache API that it
19:29
either fetches some data and returns to you
19:32
or it would just pull it out from the cache and return it to you. So
19:37
by returning promise.resolve with some data, it
19:42
just turns your static data like
19:44
promise.resolve 42. It turns it into
19:46
a promise that immediately resolves to 42. And
19:50
that's great if you're trying to like keep
19:52
the chaining or your, your,
19:54
your passing something to a function that expects
19:56
a promise. and
20:00
not just a straight up value. So
20:02
I think a sink await kind of did away with
20:04
the need for most of this stuff because if you
20:07
have an async function that returns 42, that's the same thing.
20:12
But if you need to
20:14
turn a function that
20:16
returns a value into a function that
20:18
returns a promise of a value, that's
20:21
where you use reject and resolve methods. The
20:24
static ones on P promise. Hmm.
20:29
That's what are we out here? 23
20:31
minutes? Yeah, that's enough for a part
20:34
two. Hopefully you learned a thing or two
20:36
on next Monday. We have the third installment
20:38
of the series coming out where we're going
20:40
to talk a little bit more about queuing
20:43
and concurrency and running promises in
20:45
series and a whole bunch of
20:47
libraries that are helpful for working
20:49
with this type of stuff. Take
20:53
all right. Take it later. Peace.
Podchaser is the ultimate destination for podcast data, search, and discovery. Learn More