Promises and Async/Await with Val Karpov - VUE 191
Today Steve talks with Val Karpov, the lead maintainer of Mongoose, the most used database framework on NPM. Val gives a brief history of Promises and Async/Await, talks about how they work. We learn the reasoning behind the new functionality, and how it works in VUE. Be sure to check out Vals book and his blog articles on The Code Barbarian and Mastering JS.
Hosted by:
Steve Edwards
Special Guests:
Val Karpov
Show Notes
Today Steve talks with Val Karpov, the lead maintainer of Mongoose, the most used database framework on NPM. Val gives a brief history of Promises and Async/Await, talks about how they work. We learn the reasoning behind the new functionality, and how it works in VUE. Be sure to check out Vals book and his blog articles on The Code Barbarian and Mastering JS.
Sponsors
Links
- Mongoose
- Mastering Async/Await v1.1.0
- The Code Barbarian | www.thecodebarbarian.com
- Mastering JS
- The Far Side Comic Strip by Gary Larson - Official Website | TheFarSide.com
- GitHub: vkarpov15 - Overview
- GitHub - vkarpov15/simple-promise: Simplified implementation of promises for learning purposes
- Overview - Nuxt 3 Essentials | Vue Mastery
Picks
Transcript
Steve_Edwards:
Hello everybody and welcome to yet another exciting, thrilling episode of Views on View. I am Steve Edwards, the host with the face for radio and the voice for being a mime, but I'm still your host. And today I'm flying solo as a panelist, but I have a frequent and amazing guest, Val Karpov. How you doing, Val?
Val_Karpov:
You're doing great. How are you doing, Steve?
Steve_Edwards:
Good, good, I'm enjoying some nice weather here in the Portland area for a change. We had rain through like mid-July I swear, so it's nice to get some sun.
Val_Karpov:
Yeah, that
Steve_Edwards:
And
Val_Karpov:
sounds
Steve_Edwards:
then listen
Val_Karpov:
good.
Steve_Edwards:
to all the Portlanders complain about how hot it is, but that's besides the point.
Val_Karpov:
You guys are spoiled. I live in Miami. It's hot all year round and now it's even more hot. Miami has
Steve_Edwards:
Oh yeah.
Val_Karpov:
seasons. There's hot and somewhat dry and then really hot and really rainy. And we're in the really
Steve_Edwards:
Ha ha
Val_Karpov:
hot
Steve_Edwards:
ha.
Val_Karpov:
and really rainy part of the year. Although it's been a surprisingly dry summer.
Steve_Edwards:
That's good. Yeah, that's good. Yeah, we don't have much humidity here, so I know you get a bit of that, right?
Val_Karpov:
Yeah, quite a lot. You get used to it after a few years.
Steve_Edwards:
after
Val_Karpov:
But yeah,
Steve_Edwards:
a few
Val_Karpov:
coming
Steve_Edwards:
years.
Val_Karpov:
from the Bay Area, it was a big transition, bit of a culture shock.
Steve_Edwards:
Yeah, when back in November, the week of Thanksgiving, my family and I came down to Orlando and did the, you know, the Disneyland and theme parks. And we were at Lego land one day. And when we were going in, uh, talking to the guy at the gate, my mom was talking to him and it was actually somewhat sort of a cool day. It's like for us, you know, around 70 or something like that. It was pretty decent, a little cloudy.
Val_Karpov:
Yeah.
Steve_Edwards:
And she asked something about the weather and to the guy and he. His comment was long lines. Yeah, it's nice. Right now it's pretty nice. As a lot of times it's like, he called it the third level of Hades, I think was his
Val_Karpov:
Hahaha
Steve_Edwards:
description for the temperature and the humidity. But yeah, we actually had a nice day that day. So, we are gonna talk some geeky JavaScript duffs today. We'll get into Vue probably, a little bit down the road, but Val has a book. on Promises and Async Await. And I'm looking for the link and I totally forgot what the actual title is.
Val_Karpov:
It's called Mastering Async08. The website is just async08.net. No spaces, no dashes.
Steve_Edwards:
Right, and we will put that into the show notes for those of you that don't like to type into your browser and just want to click on links. But let's get to, first of all, before we get into the nitty-gritty, you're well known in the podcast and JavaScript world, but why don't you just give us a brief background who you are, why you're famous, what you work on, etc.
Val_Karpov:
Yeah, most people know me as the maintainer of Mongoose. It's an ODM for Node and MongoDB. Most use database framework on NPM. Cool little accomplishment there. I also blog at thecodebarbarian.com and masteringjs.io, and I run a small dev shop here in Miami Beach called Minit Software.
Steve_Edwards:
And since we are Vue, we got to talk about Vue. So obviously most of your work is on Node, as you mentioned, but how often do you get to use Vue and do some front-end type of work?
Val_Karpov:
I'd probably say like three or four days a week I'm doing at least some view. For the most part I try to keep my front ends in view. I do kind of, I joke that I am like a quadzilla in the back end front end stack. You have like full stack developers who are very front end heavy and that's like the guy with the big biceps but chicken legs, I'm
Steve_Edwards:
Hahaha.
Val_Karpov:
the opposite. I do a lot of back end and occasionally do some front end.
Steve_Edwards:
They're real skinny
Val_Karpov:
Oh yeah.
Steve_Edwards:
arms, right?
Val_Karpov:
Yeah, exactly.
Steve_Edwards:
Yeah,
Val_Karpov:
So
Steve_Edwards:
like
Val_Karpov:
yeah,
Steve_Edwards:
we were talking
Val_Karpov:
three or
Steve_Edwards:
about
Val_Karpov:
four
Steve_Edwards:
ahead
Val_Karpov:
days
Steve_Edwards:
of
Val_Karpov:
or
Steve_Edwards:
time.
Val_Karpov:
two
Steve_Edwards:
It's
Val_Karpov:
more,
Steve_Edwards:
like,
Val_Karpov:
and
Steve_Edwards:
I
Val_Karpov:
then
Steve_Edwards:
don't
Val_Karpov:
the day
Steve_Edwards:
use view
Val_Karpov:
is brief.
Steve_Edwards:
very often. What is it? I don't do front end very often. When I do, I do use view.
Val_Karpov:
Yes, exactly. I
Steve_Edwards:
Thanks for watching!
Val_Karpov:
have one client that does React, but they don't really like using React and I'm kind of just stuck with that code base. But other than that, yeah, other clients use Vue, so I probably have about four or five different Vue projects that I work on right now. Rather, applications that use Vue as their front end.
Steve_Edwards:
Right, yeah, I am so going to a meme generator and creating that meme for you when we're done here. I can already see it. most interesting
Val_Karpov:
Bye bye.
Steve_Edwards:
man in the world for sure. Okay, so let's talk about promises and async await because you know obviously one of the beauties of JavaScript as compared to something like maybe PHP or Java is the asynchronous nature where you can send a request and then go on do what you're doing and then have it come back and say hey I got your stuff right? So you're not tying up, you're freezing your whole webpage waiting for this particular request to fire. I think one of the best examples I ever saw that illustrated this was a set of pictures using a bank teller. And considering my first job out of college was as a banker for a while, it sort of struck home with me. You know where you have the... Bank teller standing there and a customer comes up says, hey, I want to get into my safe deposit box. And so the teller gets another employee says, hey, go handle this. And then she takes the next client and then the next client wants to do something and she can hand it off as compared to having to go get the safe deposit box and do all that before coming back and dealing with the rest of our clients. Is that a pretty accurate description?
Val_Karpov:
That is a great metaphor. I really like
Steve_Edwards:
Metaphor,
Val_Karpov:
that.
Steve_Edwards:
there we go, that's the word I was looking for.
Val_Karpov:
I will absolutely steal that. That metaphor is perfect. That's
Steve_Edwards:
Yeah.
Val_Karpov:
a very accurate description.
Steve_Edwards:
Okay. So, how about a little bit of history of async, wait and promises, which came first and what is the second supposed to do that the first didn't?
Val_Karpov:
Well, promises came first, async await came later. If you've been around JavaScript as long as I have, you'll remember when everyone used callbacks for everything. It was especially painful in Node because trying to do more like three or four requests in using callbacks was very painful. And then if you tried to add in if statements, some sort of conditional logic, it would get really out of hand really quick. So there were libraries like async that promised to make it a little bit better. But I think around 2014, Promises really started becoming popular and started really consolidating in the node space. And then when ES6 came out in 2015, they included Promises as a core part of the JavaScript language spec. So now you have a Promise class built into, well, every browser, into node, into every JavaScript runtime. So.
Steve_Edwards:
Yes, the term that comes to mind that I remember is callback hell. I think where you have the whole, you know, pyramid that slowly goes off to the right and then back to the left, you know, as your callbacks
Val_Karpov:
Yeah, yeah.
Steve_Edwards:
get handled.
Val_Karpov:
Callback to all other terms I heard was Pyramid of Doom, and
Steve_Edwards:
Yes.
Val_Karpov:
favorite was Banana Code.
Steve_Edwards:
Banana code, okay, yeah, that fits too. Yeah, I was Angular 1. AngularJS is where I first started seeing that. That was my first foray into JavaScript. I can still remember writing some controllers like that for sure.
Val_Karpov:
Yeah, if you remember correctly, Angular 1 did actually have a Promise implementation where you could inject Q, which was an early user land Promise library.
Steve_Edwards:
Hmm, okay.
Val_Karpov:
That was a long, long time ago.
Steve_Edwards:
Right. And then, okay, so let's talk about how promises work and what they do. I know most people, you know, they have the, what's it, the resolve and the reject parameters. And then you have to append then to wait for the promise to resolve. And that's just high level gobbledygook. So can you give a little more accurate, shall we say, detailed
Val_Karpov:
I
Steve_Edwards:
description of how promises work?
Val_Karpov:
mean, that's a pretty accurate description of how you use promises. Under the hood, a promise is just a state machine that represents a potentially async operation. So like a promise starts out in pending state, which just means like, okay, operation has started. It may or may not finish at some point. And then the promise either transitions to fulfilled, as in the promise is... completed and has a value or rejected as in there was an error that occurred. So that's where resolve and reject come in. So if you create a new promise using like the, using new promise in JavaScript you pass in a function called the executor function and JavaScript calls your executor function with, with two parameters resolve and reject. Your executor function is then responsible for calling either resolve to, to fulfill the promise. or reject to say that the promise rejected through an error.
Steve_Edwards:
Okay, so let's get into a real example. Probably one of the most commonly used, I would guess, uses of a promise is making an API call. You're on your front end, you need to get some data from your backend, whatever language it is, whatever type it is, you name it. And so you're gonna make your call, and then when it's resolved, you would wanna return a resolve. And if for some reason there's an error, you know, 422 or 500, 404, and how many other cool sounding numbers I can throw out there. Then you would pass or reject, which basically tells your calling code. Sorry, I didn't, I didn't get what you wanted, right?
Val_Karpov:
Yeah, exactly. So that's like if you were to say, write a, write a promise based wrapper around like a callback only API, like say like HTML or XML, HTTP request. That's the one. Most, most API is like, like fetch and Axios. They act, they return promises for you. So you don't need to do resolve or reject yourself. They do it for you, but you can imagine like if you were writing like your own fetch polyfill or whatever. you would do something along the lines of return new promise, pass in a function that takes in resolve and reject, do some logic to make an HTTP request. If ready state equals four or whatever the thing is for XML HTTP request, then fire resolve, otherwise fire reject. However, there is some nuance as to whether or not a 400 error counts as an error. That's actually one big difference between Fetch and Axios. So with Fetch, if you make an, or with the native Fetch API in browsers, let me be explicit on that. If you use the native Fetch API in a browser, make an API request, the API request returns, like an HTTP 409, Fetch will not project the promise. It will resolve it with a status of 409. it will only throw an error if there's like a network connectivity issue. Axios is different in that it will throw an error if there's a connectivity issue, if it like can't talk to the server for some reason. It will throw an error, a slightly different error, and it will throw a slightly different error if the server returns like a 409 or 422 or 500.
Steve_Edwards:
All right, so I remember there was one app I was dealing on where I was using, you know, standard address to a Java backend. And it was difficult. One of the things I had to deal with was console error messages, which I guess aren't a big deal to the end user. But if I would make a request, I had to see if something existed, right? And so you
Val_Karpov:
Yeah.
Steve_Edwards:
pass an ID value for whatever your entity is and it didn't, so you'd get an error in your console. Sorry, this didn't exist, even though that was really only the way to tell.
Val_Karpov:
Yeah,
Steve_Edwards:
So you're getting an invalid
Val_Karpov:
that was probably
Steve_Edwards:
error.
Val_Karpov:
fetch.
Steve_Edwards:
Huh?
Val_Karpov:
That was either probably fetch or the API was returning a status code that was something that was actually indicative of the request succeeding but then contains an error, which is also
Steve_Edwards:
Great.
Val_Karpov:
possible. Like GraphQL, I'm pretty sure the memory serves like the underlying HTTP request to GraphQL will still return a 200 even if there's some error. I don't remember the exact particulars. I'm probably one of the few people that actually makes native HTTP calls to occasionally make GraphQL requests, mostly because I don't use GraphQL very much.
Steve_Edwards:
Yeah, I've seen that before where, and I've had to write code before that, where 200 is returned, it's successful, but there's nothing there, or there's an error or something, which is always fun to deal with for sure.
Val_Karpov:
Yeah, it's always fun to, you know, determine what constitutes an error versus what doesn't.
Steve_Edwards:
Mm-hmm.
Val_Karpov:
That gets to
Steve_Edwards:
Great.
Val_Karpov:
the stuff. I have like a weird philosophical question that's probably a little too boring to get into on a podcast.
Steve_Edwards:
Right. Yeah, that's in the weeds for sure. So now, you know, Axios, you've mentioned Axios, and that's, I think, one of the most, if not the most used, most used API, you know, library for making calls to, you know, to endpoints and getting data and so on. And
Val_Karpov:
Yeah.
Steve_Edwards:
so that, so if you make an Axios call, it will return a promise. So then you need to handle the... with success and error stage, right? So usually it's called, it's a thenable promise. So you, you know, do a.then, which picks up, which it calls if you had success, then you can do whatever you need to do with the data, right?
Val_Karpov:
Yeah, more or less. Venable is a different term. So like
Steve_Edwards:
Oh, okay.
Val_Karpov:
a venable is a superset of a promise where like all promises are venables, but not all
Steve_Edwards:
Mm-hmm.
Val_Karpov:
venables are promises, specifically because like to be a promise in JavaScript, you need to be like strictly instance of promise. Whereas
Steve_Edwards:
Oh,
Val_Karpov:
a venable
Steve_Edwards:
okay.
Val_Karpov:
means like any object that happens to have a.then function.
Steve_Edwards:
Mm-hmm.
Val_Karpov:
And that is actually very important for async await. And... kind of useful for promises as well too, because if you want to begin to promise chaining, because that's a good segue from
Steve_Edwards:
I was
Val_Karpov:
the pulse.
Steve_Edwards:
just about to go there. I was just about to go there actually. I was talking with that and multiple promises. So I was talking with Drew Baker earlier today. He's a big NUX guy that lives in LA and he's been a panelist on here before with me. And he said that one of the questions he wanted me to ask you was about, he said, be sure to ask how to do multiple async requests in parallel.
Val_Karpov:
Hahaha
Steve_Edwards:
Using a. Promise is all I think is the answer. So we can get to there. But yeah, let's talk about chaining because I've even seen callback hell with promises where you do a then, and then you wanna do something else based on that, and then something else based on that, which is a real life scenario. You're
Val_Karpov:
Yeah,
Steve_Edwards:
not
Val_Karpov:
unfortunately.
Steve_Edwards:
always gonna get everything you need from one API call. So
Val_Karpov:
I would say
Steve_Edwards:
what's
Val_Karpov:
that
Steve_Edwards:
the...
Val_Karpov:
for the most part, like, if you're using promise chaining correctly, you're not going to end up with a true pyramid of doom or banana code. But I find
Steve_Edwards:
Mm-hmm.
Val_Karpov:
that a lot of people use, they tend to end up using promises in a callback-like fashion, where they do, okay, promise1.then, okay, and then within the then callback, the first parameter to.then is a function called onFulfilled. So like you pass in an unfulfilled function, and JavaScript, or the Promise library, is responsible for calling your unfulfilled function if the promise is fulfilled. So then people go into their unfulfilled handler, they get another promise and call.then. Pass in and on filled to go into that on fulfilled and do promised up then on another promise And then you start looking at you start looking at basically callback hell or pyramid of doom or banana code all over again and there
Steve_Edwards:
That
Val_Karpov:
Yeah,
Steve_Edwards:
makes me dizzy just hearing that.
Val_Karpov:
that pattern is surprisingly like it's tempting if you are uncomfortable with promise chaining And to be fair, Promise chaining, like when you first see it, you kind of need to like scratch your head and be like, huh, does this actually work? And the answer is yes, it does. Because the key, so one detail that like you need to, that people don't really unwrap enough about the like core Promise API, is that you notice how the first parameter to the executor function is called resolve, not fulfill. even though a promise is either fulfilled or rejected, not resolved or rejected.
Steve_Edwards:
Okay.
Val_Karpov:
Yeah, that's actually like a really important thing that, um, that, you know, a lot of people don't really like, they'll really like get into the weeds enough to kind of understand why that's different. Um, the kicker is that if you call resolve with a non-promise value, it's the same thing as calling, it's the same thing as fulfilling the promise, right? But if you call resolve with a value, that's a promise or broadly speaking, a venable, but promise for practical purposes. So if you call resolve with a promise value, what happens is like your promise now, quote unquote, assimilates the state of the other promise. So like if I call, if I have a promise P1, within that promises executor function, I call resolve on P2. P1 is now tied to the state of P2. So if P2 resolves, P1 then resolves with the same value. and if P2 rejects, then P1 rejects. So what
Steve_Edwards:
Okay.
Val_Karpov:
happens if you, so long story short, if you have a unfulfilled handler in your.then that returns a promise, then you get back a new promise that is tied to the value of the promise that you returned.
Steve_Edwards:
Okay, so
Val_Karpov:
So it's a little
Steve_Edwards:
I
Val_Karpov:
hard
Steve_Edwards:
guess
Val_Karpov:
to
Steve_Edwards:
here's
Val_Karpov:
kind
Steve_Edwards:
what I...
Val_Karpov:
of get into, but like, okay, I make one fetch request in the.then, I return another fetch request, right? So at that point.then returns a new promise that represents the series of the first fetch request followed by the second fetch request, and resolves to and fulfills with the value of the second fetch request.
Steve_Edwards:
I'm gonna guess you cover this in detail in your book, is that right?
Val_Karpov:
Yeah
Steve_Edwards:
Okay, good, because I would be sitting here trying to comprehend that for
Val_Karpov:
Yeah,
Steve_Edwards:
a while.
Val_Karpov:
it gets a little tricky. And one of the things that I do in the book is I actually kind of walk through how to build like a Promise library from scratch that's Promises A plus compliant.
Steve_Edwards:
Uh huh.
Val_Karpov:
I also have a GitHub repo that contains a fully, a kind of like educationally oriented Promise implementation. It's like a couple hundred lines of code. It's not huge, but it does fulfill like all the spec cases for being a valid Promise library.
Steve_Edwards:
Okay, good. Well,
Val_Karpov:
That could
Steve_Edwards:
I'm gonna
Val_Karpov:
be
Steve_Edwards:
try
Val_Karpov:
a
Steve_Edwards:
to get that link and we
Val_Karpov:
work
Steve_Edwards:
can put it in the.
Val_Karpov:
in. Oh yeah, long story short with... If you're doing promise chaining, you should be returning a promise from your.then callback. You shouldn't be calling.then within a.then callback because then you're just doing callback hell all over again.
Steve_Edwards:
Yeah, I mean, that makes sense. That's generally how chaining works, right? In order to chain things on, you gotta have your full object or whatever it is, you know, passed along, whether you do it in PHP or any other language.
Val_Karpov:
Yeah, exactly.
Steve_Edwards:
Right, okay, so can you sort of describe, and maybe you've done this and I just missed it, sort of describe how that looks from a code standpoint where you have a neat sort of chaining, I mean, if you're in a promise, right, so you've defined your promise, let's say new promise, resolve, reject, and you're inside of that. But you have to return a full promise from within your promise, did I understand that correctly?
Val_Karpov:
No, you don't do that. So
Steve_Edwards:
Okay.
Val_Karpov:
with promises, there's a bit of a separation between the internals of the promise operation and the external API. So the question is, are you looking at a promise as a person consuming the promise-based API or the person writing the promise-based API? So if you're writing the promise-based API, then you're kind of doing, okay, I got resolve and reject. What do I do with the state of my promise? As a consumer of a promise-based API, you're calling.then.
Steve_Edwards:
Right. Okay. What are you passing from within your promise though that allows it to be changed. Just is it this or just that's where I'm getting confused.
Val_Karpov:
Oh, honestly, you're not passing anything. So the Promise library is responsible for handling chaining. So you can think about it as going into the, looking at it from the perspective of the person writing the Promise-based API. If you call
Steve_Edwards:
Uh-huh.
Val_Karpov:
resolve with a value that's like, okay, I'm returning this value to the consumer of my API. If I'm rejecting... That means I'm throwing an error to the consumer of my API. And then as the consumer of the API, I have no view into those internals of a promise at all. So
Steve_Edwards:
Right,
Val_Karpov:
like all I have
Steve_Edwards:
right.
Val_Karpov:
is a, another thing about promises is like you as a consumer of a promise based API, you can't reach in and take a look at what the current value is or what the current error is. All you have is.then. That's the only way that you can access the internal state of the promise. So a dub-dun is how you basically tell the promise, okay, give me a value if you're fulfilled or give me the error if you're rejected.
Steve_Edwards:
Okay. So then the need, so then getting back to this, so then we can chain them. I've seen, I've seen code examples before where you, where you've chain them and it actually looks nice and neat, right? Because you're doing then
Val_Karpov:
Yeah,
Steve_Edwards:
and you're basically stacking one on top of the other, right? Is that correct?
Val_Karpov:
yeah. Yeah, like if you're doing promise chaining right, you just have like a flat line of dot vens with no extra indentation.
Steve_Edwards:
Okay, now the
Val_Karpov:
Right
Steve_Edwards:
other thing I mentioned, sorry go ahead.
Val_Karpov:
now, obviously, there's edge cases. There are cases where maybe sometimes you wanna do a nest of then, but for the most part, if you're using promise chain correctly, it just looks like, okay,.then,.then,.then,.then, for however many lines you need.
Steve_Edwards:
Okay, so then the other thing we mentioned here briefly was waiting for a bunch of or handling them in parallel or waiting for a group of them to resolve before you go on and I've used promises all but for promise to all before is that are those two different things promise all and handling multiple in parallel?
Val_Karpov:
Promise.all is like the most common way to do, to execute multiple promises in parallel. There is also an alternative called Promise.all settled. So they're slightly different in the case of error handling. The thing with Promise.all is, so I got Promise.all returns a promise that is constructed of all the promises that is constructed. based on the promises that are passed into it. So basically, promise.all returns a promise that either fulfills with the array of all the values that the array of promises that you passed in fulfill with. So like say you pass in promise.resolve1 to promise.resolve2, promise.resolve3 to promise.all. If that promise is, if the promise that promise.all returns is fulfilled, it returns an array 123. However, if there's an error, it will only resolve with the error and the first error that occurred in the promises that executed in parallel. Promise that all settled.
Steve_Edwards:
So in other words,
Val_Karpov:
Oh,
Steve_Edwards:
Go ahead.
Val_Karpov:
so yeah. Um, so promise.all, like assume that you pass in like three different async operations. Um, promise.all will, uh, will wait until either all of those operations fulfill or until one of those operations rejects. I think that's a better way of putting it. I probably got a bit off the rails there. Um, promise.all settled is a little different in the sense that it will wait for all of the promises to, uh, to settle. A settled promise is a promise that's either resolved or rejected or fulfilled or rejected. And kind of an important detail there for Async08 is a promise that is fulfilled stays fulfilled forever and a promise that is rejected stays rejected forever. But back to promise all settled, you pass in a bunch of operations to promise that all settled and promise that all settled waits for all of the operations to settle. So either fulfill or reject. And it will return an array that. that describes whether each operation succeeded or failed and what value it fulfilled or rejected with. Does that make more sense?
Steve_Edwards:
Right, so if I understand it correctly, promise.all by itself is gonna reject as soon as it hits an error, right? Where promise.all settled, we'll wait till everything's done and then give you.
Val_Karpov:
Yeah, and then give you a collection of all the errors that occurred.
Steve_Edwards:
Okay, gotcha. So if they, if to follow your example then, if all four were to successfully resolve, so you made four calls, everything came back successful, then you're gonna do a then, I promise that all right, and you'll have your data that gets passed to you from all the different calls, I'm guessing in an array or
Val_Karpov:
Yeah,
Steve_Edwards:
an object
Val_Karpov:
in an array.
Steve_Edwards:
or.
Val_Karpov:
So like array that kind of lines up with the values that you passed in. So like you call promise.all with like A, B, C, you get out like an array that contains like what A resolved to, what B resolved to, and then what C resolved to.
Steve_Edwards:
Right, okay. Yeah, I've used that before inside Vuex now that I think about it. So cool. All right. So that's promises. Then along comes async await. So I think, you know, most people knows an attempt to make promises easier. Syntactic sugar, maybe. Is that an accurate description or what was the purpose of introducing async await syntax?
Val_Karpov:
I mean, yeah, it's an accurate description. Promises are, as we've gone through here, as you can imagine, promises are a little hard to grok. Like, I mean, they are just fundamentally a state machine, but like things like promise chaining can be a bit of a head scratcher. And then if you also add in issues like, it's kind of hard to work with conditional logic with promises, just gets a little bit messier than I would like. The benefit of async await is now you can write async code using promise-based libraries, but with kind of like CS 101 level syntax. Like you're writing for loops, you're writing if statements, you're using track catch. These are all the kind of things that like, first week of bootcamp, you probably, you would learn. So that makes it a lot easier to work with. Probably... Where Async Await really started clicking for me was at my last company, we had some iOS devs who didn't really write JavaScript, weren't really comfortable with it. If you showed them a promise chain, they would probably scratch their heads and be like, what is this? But on the other hand, they were able to contribute pretty meaningful functionality just because our backend was written in Async Await. So it was just kind of like... Oh yeah, I can kind of like muddle through and I can write a for loop and an if statement, make some changes to the code to reflect issues that I see in the field and put in a pull request, get it reviewed and yeah, ready to go. So yeah, it
Steve_Edwards:
Thanks
Val_Karpov:
makes it
Steve_Edwards:
for
Val_Karpov:
much
Steve_Edwards:
watching!
Val_Karpov:
easier for people that aren't JavaScript experts to write JavaScript.
Steve_Edwards:
Yeah, I can attest to that fact that I found it much easier to write async await than to deal with promises for sure. So now the syntax is a little different in that you basically have to declare a function as async outside and then inside you use the await syntax on whatever your promise call is. Right? So, and then if you tried to use... a weight without defining function as async, then it threw an error at you.
Val_Karpov:
Yeah, that's exactly right. So async function, new type of function, difference being that async functions always return a promise. There's no way to make an async function return something other than a promise. But if you return something from an async function body, like you have async function return 42, you won't get back 42 when you call that async function. It'll get back a promise that resolves to 42. And yeah. The benefit of using an ASIC function is you can use a weight within the body of an ASIC function.
Steve_Edwards:
Right, and so the benefit of the await is sort of, as its name indicates, right, that you can make your code do something, an asynchronous function synchronously, seems sort of a
Val_Karpov:
Yeah,
Steve_Edwards:
good
Val_Karpov:
okay.
Steve_Edwards:
description, because you get to a line and you're like, async my method, okay, so const myVal equals await axios.get, whatever, right?
Val_Karpov:
Yeah.
Steve_Edwards:
And so until that function, that. is returned, your code doesn't continue to execute.
Val_Karpov:
Yeah, that's about right. The interesting thing there is though, how to put this? Well, oh, your async function doesn't block when you call async, so when you call await or when you use await. So what ends up happening when you call or when you use await is the JavaScript runtime kind of pauses the execution of the async function. So JavaScript is still practically speaking single threaded in the sense that no two functions can run at the exact same time, right? But the thing with an async function is when you call awaitaxios.get, that function isn't running anymore. It's actually just suspended. It'll run when the Axios request is done. So if you've ever used a generator function or have used generators in JavaScript, you can do that.
Steve_Edwards:
No, and I was reading about that, something you had mentioned in one AC Generator Functions, a blog post about it from about three years ago it looks like.
Val_Karpov:
Yeah.
Steve_Edwards:
I've heard about them, haven't had an opportunity to really utilize them. Maybe I have and I just haven't known how to. I don't
Val_Karpov:
Oh
Steve_Edwards:
know.
Val_Karpov:
no, I mean, now that we have async-await, like I am, I often struggle to find a use case for generators, like async generators are still kind of useful, mostly like for like the for await const construct, like async iterators. Those are pretty cool. Generators are not as useful, but what makes generators really interesting is that they're kind of like a user land equivalent to async-await in the sense that like, A generator function is a function that executes until the first yield. And then you have a handle to that generator function that you call next on to resume execution. So a generator function executes, pauses when it calls yield, and then the code that's calling the generator function can decide when the generator function should pick back up again. So generators
Steve_Edwards:
Yeah, that's right.
Val_Karpov:
are like... kind of similar to ASIC await in a lot of ways. And if you ever, did you ever see the library co, C-O? Um,
Steve_Edwards:
No, I don't think so. Not
Val_Karpov:
That
Steve_Edwards:
ringing any
Val_Karpov:
one,
Steve_Edwards:
bells.
Val_Karpov:
from probably around 2014 to 2016 or 2017, that was kind of like the async-await equivalent. What Co did was it basically implemented something very much like async-await syntax, but using generators, because generators were introduced in ES2015 or ES6. And then Async Await came out two years later. So until Async Await was broadly adopted, Co was very popular.
Steve_Edwards:
Yeah, I'm looking through some code here, so I'm working on my day-to-day app, it's a pretty large Laravel and Vue app, and I've actually used generators in PHP in Laravel. I'm not sure if that's the same thing as the way they're used in JavaScript, but...
Val_Karpov:
I know Python's generators are pretty similar to JavaScript's. I haven't looked at PHP in a long time, so I can't really say. But I would imagine it's not too far off. If generators are something where you have a function that pauses when you yield, and then you resume it later.
Steve_Edwards:
Yeah, I used it for, I know there's, at least the PHP version, I'm looking at it and it's coming back to me sort of there. I know there's some performance issues because I'm doing some stuff with Redis and running a task behind the scenes. But that's about the closest I've come to generators, at least as in another language, for sure.
Val_Karpov:
I don't know. Generators is a whole separate topic, but async await is similar or kind of like, you can almost think of it as a native JavaScript implementation of a generator or a special case of a generator where if you yield a promise, the runtime waits for that promise to settle before it resumes your code. So if you await on a promise, what the JavaScript runtime does under the hood is it actually calls then. And
Steve_Edwards:
Hmm.
Val_Karpov:
it basically passes in an onFulfilled that returns the value that the promise fulfills with, or an onRejected that throws a catchable error. So like you can use tryCatch to catch errors in that awaitP can throw, or you can assign like the value of Or you can say const v equals await p, and you get the value that the promise resolves to. So you can think of await as unwrapping a promise, basically, but in an async-friendly way, where basically you're pausing your function execution until the promise is done, so other code can execute. In Vue, like, renders can happen and... Users can click buttons and whatnot on the node end. Other requests can be processed.
Steve_Edwards:
All right, so we mentioned at the beginning the syntax where you have async, you define your function as async, then use a weight. And then along came top level of weight. Can you talk about what top level of weight is and how it's supposed to make things easier?
Val_Karpov:
I mean, to be honest, I haven't used top level await very much, so I don't know like the nuances behind it. But the general idea of top level await is that like, you can't use await outside of an async function. So normally you can't use it in the top level of a script. So like you can't just have like a script like HTTP.js that does await Axios.get at the top level without wrapping it in an async function, right? So top level await, like in theory, lets you execute await at the top level without wrapping it in an async function.
Steve_Edwards:
Mm-hmm.
Val_Karpov:
I don't really know how that affects like imports or require how that works. In my experience, like, I don't really use top level await much just because the use cases where I think I wanna use top level await are like one-off scripts that just by kind of execute a node or like. scripts to potentially reproduce a bug in Mongoose could potentially be useful, but like, in production code, I don't find myself wanting to use top level of weight.
Steve_Edwards:
Okay, yeah, I've heard about it and haven't had really much chance to use it either, but Definitely something wanted to address since we're talking async await, right?
Val_Karpov:
Yeah.
Steve_Edwards:
Right, so Before we move on to one last topic. Is there anything else in promises or async await? That you think would be worth mentioning
Val_Karpov:
This is Views on View, we can talk about async await with view.
Steve_Edwards:
There you go. Okay, so is there anything particular to view or preference of one over the other in your experience in making asynchronous calls?
Val_Karpov:
So one thing I really like about Vue is it actually has pretty good support for async await, unlike some other frameworks. So in React, your render function needs to be synchronous. If you want to pass an async function to a useEffect hook, you're not really supposed to do that. So in React, you kind of are stuck writing sync logic. There's suspense. I haven't really played with suspense enough, but I don't think suspense has actually been formally released yet, has it?
Steve_Edwards:
It's in view three.
Val_Karpov:
Oh, I meant the React version, but
Steve_Edwards:
Oh,
Val_Karpov:
I'm
Steve_Edwards:
I'm sorry, React. Oh, that I don't know.
Val_Karpov:
not sure. Yeah, I don't know. I haven't followed closely enough. I don't know, like what I really like about, well, async await as well as view and as well as views implementation of async await is error handling. Specifically, there's the error captured hook. One of the neat things about about async await is like errors bubble up in async functions kind of the same way that they do in synchronous functions. So like let's say you have a function call three layers down the stack that throws an error that error bubbles up the stack. So you can so if you have like function A that calls a function B that calls a function C that calls a function D that throws an error. A can wrap the call for B in a try-catch and catch the error from D in pretty much the same way that you would with any sort of synchronous logic. And now what Vue adds is a neat little error-captured lifecycle hook. So similar to how you do like mounted or updated on a Vue component, you can also do error-captured, which will catch sync or async errors in methods, hooks, et cetera, from any component down the component tree. And again, those errors bubble up to the next error captured hook. So like you can actually have like, okay, um, the top level app component that has an error captured hook that captures any unhandled errors anywhere down the, uh, the component tree, whether they're synchronous or asynchronous. Um, and then you can also have like, Oh, if you want a specific error captured hook for this one portion of the component tree, you actually can just put an error captured hook, like at the root of that. subtree of your component tree and say, okay, now all the errors for this particular subsection, like everything related to the nav bar has its own dedicated error captured hook and any subcomponent of the nav bar, any errors that it throws will get handled by this one error captured hook, everything else will get another error captured hook. So yeah, the error captured hook is pretty huge just because like here's, you know, here's a way to handle sync and async errors in a way that that JavaScript really didn't have before. Does that make sense?
Steve_Edwards:
Yeah, so I think the one thing you and I had discussed earlier that's worth pointing out and you mentioned it, I think I'll just mention it specifically, is that the error captured hook is not going to catch errors, async, promise errors from the same component.
Val_Karpov:
Yeah,
Steve_Edwards:
It's
Val_Karpov:
yeah,
Steve_Edwards:
only going to
Val_Karpov:
only
Steve_Edwards:
catch
Val_Karpov:
child
Steve_Edwards:
them from
Val_Karpov:
can
Steve_Edwards:
children
Val_Karpov:
program.
Steve_Edwards:
components. So if you have a tree of component A, B, and C where B imports C and A imports B and so on, so if you had an async or promise based error in B or C, it would bubble all the way up to A. So
Val_Karpov:
Yeah,
Steve_Edwards:
your
Val_Karpov:
exactly.
Steve_Edwards:
top level, or if you wanna think parent child, one child too if it's easier, just to think of it that way. So, boy I could think of a number of places where I could use something like that for sure. Around our app, so. So yeah.
Val_Karpov:
I end up using Async Await for basically everything or everything view related. The trade-off there would be like, okay, maybe the browser support isn't as great, but the apps that I'm working on don't really worry about support for IE 10 or anything like that. That's not a priority. So I'm happy enough just shipping Async Await code and not really transpiling it. And yeah, what I really like about Async Awaited is again, it makes it easy for there, for as a technical architect, it makes it easy for me to like make sure that errors are handled in some sane way. And as like, that's kind of like my architect level thinking is basically like it's my responsibility to make sure that my team can focus on like the happy path code. maybe some error handling if there's something specific, like okay, if this Stripe call failed, we want to show something that's a little bit more detailed than a generic error message. But it's my job to make it so that they can focus primarily on happy path so I can focus on all the things that can go wrong. How do we handle when things go wrong? How do we report it? How do we make sure we can debug what's going wrong? Things like that.
Steve_Edwards:
Oh, so you don't subscribe to the black hole method of error handling where they just disappear to a black hole and you leave your users wondering what went wrong?
Val_Karpov:
I mean, yeah, I don't like that one either.
Steve_Edwards:
Ha ha ha.
Val_Karpov:
Another one that I don't really like is like, I really don't like Go's error handling syntax. We're like, go as a language has some neat benefits, but like their error handling is just unpleasant because I'm like, do I really, really need to manually bubble up every single potential error? Like that's just really annoying. And async await is kind of the opposite of that where like errors just kind of bubble up by default and you don't really need to think about it. Like the other interesting kind of like nuance with error captured and promise chaining is that error, if Unless you return a promise from a function, ErrorCaptured won't catch any errors that happen in that promise chain. So
Steve_Edwards:
Oh.
Val_Karpov:
you want to replace a function, an async mounted hook, with a mounted hook that returns a promise chain. You need to make sure that you're returning that promise chain, because if you miss that return statement, ErrorCaptured won't handle any errors up top. And that's simply because, again, async function, async, functions always return a promise. So that means that Vue has the ability to look into that async function and catch any errors that occur. But if you have a function that uses a promise chain but doesn't return that promise chain, there's no way to catch any errors, or any unhandled errors that occur in that promise chain. If you get what I'm saying, does that make sense?
Steve_Edwards:
Yeah, I do at least. At least conceptually right now. I suppose when I get down to write it I say what? But at least in my head right now I get the picture for sure. So, all right. So that's a lot of mind-numbing stuff on promises and async await. Before we move on to picks, anything else that you think we should discuss, cover about those two?
Val_Karpov:
Um, not at the moment. Um, is there anything that you wanted to, uh, wanna hear a little bit more about?
Steve_Edwards:
No, my brain is full. If you've ever seen that classic Farsight cartoon where the kid raises his hand and says, excuse me, I'd like to leave, my brain is full, that's my brain right now.
Val_Karpov:
That sounds like a good pic to share, because I don't...
Steve_Edwards:
Yeah, I have to see because I know that Gary Larson has a Far Side site now. For a long time he went, him and his syndicate went after anybody that posted Far Side cartoons anywhere on the internet and said, hey, you want to take this down? This is copyright. And so you couldn't find anything posted anywhere. But now that he's got his own site, thefarside.com. He's posting a lot of stuff. I haven't looked in a while, so that one might be out there. If I can, I'll put a link, but yeah, that's a classic. For sure, for sure. So we'll move on to picks. Picks are things that we like to talk about that maybe aren't code related, since we do have lives outside of coding, at least some of us. Books, movies, food, travel. you know, you name it. I will start out just to give Val a little more time to contemplate if he has any picks. Speaking of cartoons, I happened to come across this item today on Hacker News, and it is a Calvin and Hobbes search engine. So a guy named Mike Yingling wrote it, and he talks about how there's a couple different scripts. collection of strips on various websites and so he's combined them to for you to be able to type in some text and and find certain cartoons. I know my kids when they were much younger were avid readers of Calvin and Hobbes so I have seen most of them if not all of them at some point in my adult life and even when they were first being published. So it's a michaelyingling.com random Calvin and Hobbes. I'll put the link in the show notes.
Val_Karpov:
Thanks for watching!
Steve_Edwards:
And then as usual, the anticipation of most everybody listens to these podcasts are the dad jokes of the week. Not really, but I'll say that anyway.
Val_Karpov:
As a new dad, I look forward to these.
Steve_Edwards:
Yes, so let's do some of my more recent ones here. I have a I post them in Slack everyday for work, too So I have a quite a between that and Twitter. I have quite the collection going here. So I've been told this one is old a bit. This is the first time I heard it and I liked it anyway, so What is worse than finding an apple, excuse me a worm inside of your apple?
Val_Karpov:
I don't know.
Steve_Edwards:
Half of a worm.
Val_Karpov:
haha
Steve_Edwards:
for finding half of a worm inside your apple. That's sort of, yeah,
Val_Karpov:
That's pretty
Steve_Edwards:
not
Val_Karpov:
good.
Steve_Edwards:
good. Right, excuse me. So we know our superheroes, right? Batman, Superman. So Superman has supervision, obviously. Why doesn't Batman have supervision? His
Val_Karpov:
Because
Steve_Edwards:
parents
Val_Karpov:
he's blind,
Steve_Edwards:
died.
Val_Karpov:
isn't that?
Steve_Edwards:
No,
Val_Karpov:
Oh.
Steve_Edwards:
his parents died, get it?
Val_Karpov:
Oh, that's uh... That's pretty good.
Steve_Edwards:
super little morbid I know but but
Val_Karpov:
Oh, I got one for you. So
Steve_Edwards:
Go for it.
Val_Karpov:
my kid walked up to me and said, Hi, Daddy, I'm hungry. So I responded, Hi, Hungry, I'm Daddy.
Steve_Edwards:
That has to be one of the oldest in the book, but it's a classic. It's a very
Val_Karpov:
I
Steve_Edwards:
good
Val_Karpov:
love
Steve_Edwards:
one.
Val_Karpov:
that one.
Steve_Edwards:
Yes, it is. My kids, dad, knock it off. Sorry.
Val_Karpov:
I look forward to my kid being old enough to tell me to knock it off.
Steve_Edwards:
How old is he now?
Val_Karpov:
She's nine months.
Steve_Edwards:
Or she, sorry. Nine months. Yeah, that's a little bit young for the dad jokes yet, but it's never too early to start, to be honest. You know, I love my cow jokes. You know, like, what do you call a cow with no legs? Ground beef. You know, my more recent one was, what do you call a cow with one leg? It's a steak, right?
Val_Karpov:
Nice.
Steve_Edwards:
And so, right. So my more recent one is what is the cow emoji called? it
Val_Karpov:
Good.
Steve_Edwards:
an emoji. Finally, right?
Val_Karpov:
That's a good one. I can do this all day.
Steve_Edwards:
And then finally, what is small, red, and whispers?
Val_Karpov:
I don't know.
Steve_Edwards:
A horse radish. Thank you. Thank you. Alrighty, so your turn now that I've buttered you up. Grease the skids, however you want to call it. What do you got for us for picks?
Val_Karpov:
Let's see here. So I've gotten into this new hydration supplement called LMNT, or just like elements. I don't know how you pronounce it. Really good, very tasty, got lots of magnesium, so it's really good for you. Check it out. Let's see. And another note. Oh, let's see. I've been getting more into watching kid-friendly TV lately because I have a nine-month-old. So
Steve_Edwards:
Right. Yes.
Val_Karpov:
I most recently finished watching this Netflix original series called Alexa and Katie. That one is really heartwarming
Steve_Edwards:
Really?
Val_Karpov:
and really fun. It's about like the high school experience of a girl who's fighting leukemia. So it sounds
Steve_Edwards:
Ooh.
Val_Karpov:
like it should be dark and gritty, but it's actually really fun and just endearing. So
Steve_Edwards:
Oh, really?
Val_Karpov:
worth checking out. It's a lot of fun.
Steve_Edwards:
My daughter's name is Alexa and you know back then I thought
Val_Karpov:
Oh no, my
Steve_Edwards:
it...
Val_Karpov:
daughter's name is Alexandra.
Steve_Edwards:
Well, yeah, back then I thought it was really unique, cool name. And then she got older. I found that it wasn't so unique. And then when Amazon Alexa came along, of course, she's been tired of hearing that, you know, working at athletic club, people come up, Alexa, do this. So Alexa, do that. Yeah. Okay. I get it. Funny. Thank you. That died a long time ago. Cool, any other picks?
Val_Karpov:
I love the holograms on the show. Let's see, on a more, I guess like on a more technical note, maybe it's the right place to link to that Promise implementation that I told you about. Oh, okay.
Steve_Edwards:
We'll categorize this under shameless plugs. I have a shameless plug myself, so this will work perfectly.
Val_Karpov:
That's fair, all right. So shameless plug. There's my ebook, async-await.net. I need to come out with version 1.1 came out about a year ago. I need to come out with version 1.2. Big change will probably be that version 1.2 will focus more on view as opposed to React because when I first wrote the book, I was doing like a little bit more React and I was like kind of not sure where I wanted to go with front-end frameworks. Since then, I've decided, yeah, I'm just doing everything in view going forward. It's been a wonderful two years since I just made that decision.
Steve_Edwards:
Awesome.
Val_Karpov:
AsicAwait.net and github.com slash vcarpout15 slash simple-promise is the simple promise implementation.
Steve_Edwards:
Simple promise. All right, we will get
Val_Karpov:
Yeah,
Steve_Edwards:
that into.
Val_Karpov:
how simple it is is up to you, but it's simpler than reading Bluebird or Q. I can guarantee you that.
Steve_Edwards:
And what are bluebird and Q? Sorry, I'm not.
Val_Karpov:
They're popular user land promised libraries. Bluebird was pretty popular up when Promises first came out because it was very fast.
Steve_Edwards:
Mm-hmm.
Val_Karpov:
It was faster than Native Promises for a long, long time before Native Promises caught up.
Steve_Edwards:
Mm-hmm.
Val_Karpov:
And Q was one of the early movers in promised libraries.
Steve_Edwards:
Awesome. All right. My shameless plug I've mentioned previously is there is a new course at Viewmastery.com that I have recorded and is in the process of being released. It's called Nux 3 Essentials. It's a very basic course on Nux 3, how to get up and running with it, how to use setup scripts. and a number of things, just like I said, real basic introductory, but it uses, we're using use fetch inside of Nuxt 3 to query a cryptocurrency API and display some data for the user. So you can see that at Viewmastery.com and I'll throw a link in there for those who are into masochism. I'm just kidding. No, it's actually a very good course. And the bonus is at the end of every episode, you get a dad joke from me. I forget the title that they use is something about really bad dad jokes or horrific dad jokes or something like that, but they're still funny. So at least I think so. So anyway, all righty. That is going to wrap it for this episode of Views on View. Thank you Val for coming on. That was great. He certainly got more stuff to talk about. So hopefully we'll get him on here in the future and talk about other view specific things. And in the meantime, adios and we'll talk at you next time.
Promises and Async/Await with Val Karpov - VUE 191
0:00
Playback Speed: