about 2 years ago Syntax Podcast
JS Promises Fundamentals - Part 1
- 02:06 Promises help handle asynchronous actions like network requests
- 03:00 Promises represent data that will be available later
- 03:43 Fetch API returns promises for network requests
- 06:03 Database queries return promises
- 07:20 Browser permissions like webcam access use promises
- 08:21 Promises can resolve with data or reject on failure
- 10:08 You can create promises manually or with async functions
- 15:07 .then, .catch, .finally wait on promises
- 16:46 async/await syntax is preferable for readability
Fetch API returns promises for network requests
Wes Bos
often, I'm in that camp. Like, Node. Maybe we don't need a very opinionated way to do this in the language, but with with promises being able to have a single type.
Wes Bos
Being able to have it as a primitive in the language it will have that it'll work just fine. The same thing with rejecting. You don't have to explicitly reject.
Wes Bos
Another example of promises would be a database query or an insert command, pretty much any database ORM that you're using these days.
Scott Tolinski
If you go off and you know, there used to be libraries, and now we have a standardized
Wes Bos
Yes. And the promises being a feature of the language has been queuing, flow control, The other one being that sometimes you want
Scott Tolinski
If you go off to grab some data from anywhere, and you're most likely using fetch. And if you've ever tried to access that data immediately,
Scott Tolinski
And then and you say, alright. Let me You just return the promise from that function,
Scott Tolinski
then you can, you know, bring that data back, and now we can do something with it. So you've gone off to a trip to the store. You've now come back with the goodies that you you ordered.
Wes Bos
And it's not really, like, a new thing, but it's it's a new API that makes working with deferreds a little bit easier. And a lot of people are like, why are they adding all this garbage? Why don't you just go and use this library that already did it really well? And create user. Whereas the create user function would return a promise, putting in a weight in front of it will will sort of unwrap the promise. It will wait for the promise to resolve and give you the actual data at the end of the day. A weight also is used for generator functions, but we're not getting into that in the promise episode.
Scott Tolinski
fetch API.
Scott Tolinski
wait for that data. Or when when the data does come back or perhaps you failed to get to the store,
Scott Tolinski
you'll know that it returns a promise.
Wes Bos
a promise or or a way to do this type of work. But Mhmm.
Wes Bos
API that does validation Wes you wanna stop your code from running. You wait for something to show up on the page, and then when that thing is on the page, it will resolve. We'll talk about that in just a second, library normally, the the result of a promise is returned immediately.
Wes Bos
means that you can mix and match
async/await syntax is preferable for readability
Wes Bos
that I've seen is And then, a little wait function is a example of a promise that you might write yourself. So the data that that promise has set out to to go get or to to go and then And You can throw an error, which you might be used to already. You Sanity, you may want to return And if you have to get JSON back, you know it's JSON.
Wes Bos
or you create, like, a a variable that's Node the scope of the dot then and you sort of update it. That's annoying because now you have like an undefined variable for a short amount of time and you have TypeScript. That's a bit tricky.
Wes Bos
I personally do that as well as I await, but I'd use a dot catch to to catch the error in in most cases.
Wes Bos
any, and race,
Scott Tolinski
layer deep. Right?
Wes Bos
canceling promises, aborting promises,
Wes Bos
if you return another promise from that dot then, you can chain them
Wes Bos
which is hard, and it's also really hard to, like, pass data between the 2 of them. So if you
Scott Tolinski
going another where you can use the resolve or reject methods to, like, Wes mentioned moments ago,
Wes Bos
you can continue ongoing. So it's a beautiful API because you can simply just say, like, const user equals await return immediately.
Scott Tolinski
async function. I don't feel like making this function async, so I'll just throw a dot then on there.
Wes Bos
weather data. And then that's really frustrating because where
Wes Bos
for Wes something is resolved, but keep the function going I'll have from a function that will return you data right away, turns into a function that will return a promise Yeah. That's, that's something we have coming up in the next one, which is error handling strategies of, like, mix and matching.
Wes Bos
stream and from running.
Wes Bos
The fetch has, like, a double promise thing, which we'll explain in the in the next episode. Sometimes I'll just chain a little dot then on top of it.
Wes Bos
onto one another.
Scott Tolinski
await just because it reads more like how I would expect it to work, and then I can access the values where I want to access them. Alright. Wait for the value. It's there. Now I can do something with it. But, you know, there certainly are times where I am using a a catch or a dot then as well. I do use a dot catch Sick.
Wes Bos
yeah, I like I like the the strategies. How do you how do you specifically And then the next line below that, you wanna set up, like, an event handler
Wes Bos
once the promise resolves itself,
Scott Tolinski
to your promise of future episodes. Promise it will be good. Peace. I can't When you go off to do a fetch, it it doesn't know how long that's going to take. It says, I'm gonna go get some data. I'll be right back.
Wes Bos
the async await API simply because it reads a lot nicer.
Wes Bos
a dot then, and that will return to you the promise itself, but also the reject
Wes Bos
to listen And if you have a async functions is that inside of an async function, you can simply just return a value.
Scott Tolinski
it is funny because it sometimes it feels haphazard in which I I'll be like, oh, I'm not inside of an
Wes Bos
wait.
Wes Bos
you find yourself having to modify and all of those things need to happen inside of your promise. They can also often chain them together. And then when you're successfully done, you resolve it. If there's an error anywhere along the way, you can reject that promise and say, this is this is explicitly what has happened.
Wes Bos
and put a single dot catch at the end of it, any errors that happen along the chain. Where that becomes an issue is then you have your a weird scope, as well as 5 different ways to handle
Scott Tolinski
variable and pass it and worry about the default values before and after the the promise return. So almost always, I'm using
Wes Bos
you want to go off and fetch something.
Scott Tolinski
I to me, it depends on, like, what I have to do with that data. The thing that's always bugged me about the then methods
Wes Bos
some of the promise helpers, which is all all settled, finally, It was very hard to say, alright. Well, I'm gonna work with this database adapter, while you're waiting for it. So a very common use case
Scott Tolinski
I look forward Yeah. My default is Yes. And I don't think this necessarily fits ESLint there, but there's also
Scott Tolinski
is that you're now I think this is a great idea, though, because, you know, I remember when I first learned about promises black back when they weren't in the browser, you had to use q or Bluebird or one of those. Right? Yeah. I remember being very confused about
Wes Bos
now if you wanna comment Node of them out, then you have to change the signatures again,
.then, .catch, .finally wait on promises
Scott Tolinski
a third one that a lot of people don't use, which is finally,
Scott Tolinski
If the promise rejects, you would then need to also chain a dot
Scott Tolinski
then you say you have a function call, right, obviously, and then you chain a Scott then to the end of that.
Scott Tolinski
and then that callback
Scott Tolinski
catch.
Wes Bos
and you need to turn the loading state off in both cases. Right? And after a successful return or, We'll talk a little bit more about error handling and and how to mix and match them. There are use cases where you still want to use the dot then. Chaining is is a really nice one instead of just doing await await await. Some people like to chain then then then
Scott Tolinski
which this will go no matter what. So if you find yourself duplicating some logic, maybe, like, you're waiting for a value and then you're setting a state toggle based on that value, if that state toggle is toggled Deno matter what, if there's an error or a fit a success state, you could put that in your finally. So the finally is gonna run no matter what after the catch and after the then.
Scott Tolinski
has the data that's available to you if that promise is resolved correctly.
Scott Tolinski
Dot then has a callback,
Scott Tolinski
You then need to chain a a dot catch in which the error will be available in the callback function. And then there's also,
Scott Tolinski
Alright. Well, let's talk about waiting on those promises. Right? So the main way that a lot of people have done it is with a dot then method.
Wes Bos
on error, I wanna turn the loading state off.
Promises represent data that will be available later
Wes Bos
a promise from the user.
Wes Bos
I will I have tweeted screenshots of code that I've written, and I'll just, like, mark a function as a sync, and then I'll, like, I'll refactor it to return a promise.
Wes Bos
I'm gonna fail, which is is called rejecting.
Wes Bos
And I thought, like, let's just kick it off with just some common examples of what a promise would be. I know most people listening sort of understand what a promise would be, but let's let's talk about So database queries, every ORM that you work with will return to a promise, and then you can sort of just wait for that to for when somebody clicks something or when a specific event happens. If you were to await that fetch request, the event handler would never run until because you're essentially pausing the use case. Same thing with streams as well. That's pretty common use case Wes, all right, I'm going to set up this
Scott Tolinski
anything. The most common one being you wanna take this 1? Yeah. And I think the one that most people have used is fetch calls.
Wes Bos
any type of data that can be returned from a promise, which is indefinitely There's a new method, which I'll talk a bit more about in a future episode, this idea of deferreds.
Wes Bos
give you some piece of data or
You can create promises manually or with async functions
Scott Tolinski
Yep. And here's a a small little thing for people who find themselves doing this.
Wes Bos
having a function marked as a sync if you are returning a promise.
Wes Bos
throw a new error. User email has already been registered.
Wes Bos
in front of it. Immediately,
Scott Tolinski
like I mentioned, we're then gonna get into, like, the waiting on a promise bit of this because, again I got sorry. I got one more thing to say about that.
Wes Bos
when you want to bundle together a bunch of functionality. And often you'll have, like, nested promises. So you might have a a promise called create user. Right? And in that create user promise So Welcome to Syntax. Today, we've got a first of 3 shows on promise deep dive. So I was driving home from,
Wes Bos
So if you were to have an async function that returns a promise itself, you're not gonna get into any weird, like, nested
Scott Tolinski
returns a promise,
Wes Bos
And then the 3rd way we have for creating a promise, and this is quite honestly
Wes Bos
at a top level. And this can be handy if you want to method. You simply just return. And because the the function has been marked as a sync, And even if it did, that's something called a synchronous request or a blocking request. And what that would do is it would actually lock up the rest of your application from running. So if you your promises.
Scott Tolinski
Alright. Well, let's talk about waiting on a promise then because like we mentioned, a promise is you know? Yeah. It's a commitment to come back and and you know? I'm promising to to go to the store and get some candy cigarettes. When I come back, I better have those candy cigarettes. Do you remember those, by the way? Did you ever get those in Canada? Yeah. It's it's pretty wild that we just, like, had even on await instead of doing a try catch, though.
Wes Bos
And instead of creating a new promise and putting all of your code inside of a promise callback, which does have use cases, you simply just future functions so that they'll accept the incoming So So, again, a promise is a stop deal with errors Word. But I think that's that's all we have for the 1st episode. Again, that was pretty high level of explaining promises. In the next episode, we're gonna get into
Wes Bos
items that are related to that user, setting a bunch of permissions, Yeah. That's that's really handy if you, like, have, like, a loading state
Scott Tolinski
what you don't wanna do is you don't wanna mark the function as async and then await that promise and then return the result.
Wes Bos
You can have other promises inside of there. And if you return either a value or a promise,
Wes Bos
the actual user once I'm done. But inside of that, you may be doing several things. Right? You may be doing some sort of validation. You might be checking if they have have 1 promise that fetches the weather and then another promise that saves the weather to the database,
Wes Bos
or a function that returns a promise, I I promise I will go and create the user and return to you, Those are reject cases.
Scott Tolinski
If your function I don't know why. I I Wes I don't know why I said that, you know, apprehensively.
Wes Bos
At least I don't know of of any, like, performance downside to, your Node that will return data at some point. And the kind of the cool thing about
Scott Tolinski
and you're returning a promise from the function rather than having to create a new promise and and do it that way. So Word.
Wes Bos
the actual promise itself from that function. There's no harm in, like, sort of double wrapping The chaining the dot thens onto each other, and I should say the way that this works is if you have
Wes Bos
you don't have to use the resolve you can sort of pause that function
Wes Bos
create a function. You mark it with the keyword async agreement that some data will be returned to you. It's a commitment. Like, a promise. Commitment. Yeah.
Wes Bos
and resolve but you could if you if you did have a blocking Something happened inside of this promise where there was an error that happened because of a different library.
Wes Bos
a sink on there, which is why I like the ESLint rule that will be like, you didn't await anything inside of this. What are you doing marking it as a sync? But I don't think there is.
Scott Tolinski
cigarettes, and they're, like, red on the tips. Like, clearly, you're trying to make these fake cigarettes. But I said you're supposed to, like, keep keep them in your mouth. I just chomped them up. That's what I did. They're, like, chomping. I can't. Yeah. I can't do that.
Scott Tolinski
thens that that will be an issue for you. Do you think there is any sort of performance implications there? I I don't know if there is. I'm just wondering. I don't I don't think so. Often,
Wes Bos
sometimes there's an unnecessary I Yes. Yes. Good. Oh, yeah. Let's see. How many promise jokes can we make in these next 3 weeks? And if you want to see all of the errors in your application, Previously, it was like Scott said, you have to use Bluebird or a sync or callbacks.
Promises can resolve with data or reject on failure
Scott Tolinski
either resolve and complete the promise or reject and fail the promise. Yeah. You are often creating your own promises So instead of using a sync await or anything like that, you have your promise,
Scott Tolinski
Wes we're working on promises.
Scott Tolinski
We'll talk about this in a bit, but that those connect directly to the then. Right? The then method is called once a promise has been resolved. The catch method
Scott Tolinski
using new promise. And you can create a promise, and that gives you a callback
Wes Bos
a negative outcome of a promise is called a reject. And often, you will call reject in your promises the most common way these days, is you mark a function, like, I know most languages have sort of the idea of
Scott Tolinski
so you resolve or reject a promise, and and those things connect very firmly to
Wes Bos
fetch for you or to you would resolve after somebody clicks a button. That's a successful outcome of a promise is called a resolve, the await whatever.
Wes Bos
successfully Resolving a promise is The user did not actually give me access to their webcam.
Scott Tolinski
gets called when something is rejected,
Database queries return promises
Wes Bos
circumstance,
Wes Bos
where you create a blocking pass the resolver and reject methods to other parts of your application rather than doing your work inside of the promise itself.
Wes Bos
successfully give you the message. Say, I save the data or resolves to the query of the data that's been returned to you. Yep. If you if you notice a pattern here where, basically, testing library at some point in the future, that surround and I'm going to be working with this
Scott Tolinski
we use a a promise. So that way, it takes something that could be blocking and makes it so it does not block the execution of other things, which is one of the reasons why we have to do the whole the whole then thing with promises that we'll get into.
Scott Tolinski
Another thing could be,
Scott Tolinski
anytime something could be blocking, If you wanna access that data outside of the promise, you have to create a
Wes Bos
If your database is not gonna solve You sometimes do have a sync functions that return promises, and and the use case for that is sometimes you want to first await something inside of that,
Transcript
Scott Tolinski
you'll want to check out Sanity at sentry.ioforward/
Wes Bos
on deep dive into promises. So today, we've got sort of an introduction, understanding in a nice way for your application with promises? pretty common way to do it, and then we also have the ability to await promises. So when you're in a function that is marked as a sync, how promises work, and awaiting them in different ways to create and listen for a promise resolve. Then, 2nd day, we're gonna have 1 on canceling promises, helper methods, and error handling
Wes Bos
dropping off my kids at school today, and I thought, like, an amazing what what should we what should we do? You know? And I have been keeping notes on just, like, all of these things The the finally is super handy for that. And, quite honestly, I don't see it used all that often. So I think I should maybe start using a little bit more myself.
Wes Bos
And then the last 1 we have is returning database right, you could run into the situation where your server's handling incoming requests or or does a bunch of queuing. And getting those to work together was always kind of frustrating. And now that we have we've had them in the the browser for for many, many years, it's much easier.
Wes Bos
working with promises in JavaScript. And I realized, like, man, there's actually quite a bit to that function changes the dot then is a anything that returns a promise, and you can work with them together. This is one thing when there's a new thing called deferreds that have been added to promises.
Scott Tolinski
syntax. Again, we've been using this tool for a long time, and it totally rules. Alright.
Wes Bos
getting into concurrency,
Wes Bos
fetch, canceling them, and deferreds,
Wes Bos
which is a new API in in the browser. So
Scott Tolinski
syntax. You can sign up today and get 2 months for free. Sentry is just a really incredible tool for not only tracking your performance, making sure your application has no bugs, but even just seeing what goes wrong when something goes wrong because things go wrong all the time when we're coding. And you don't want a production application out there that, well, you have no visibility into in case something is blowing up, and you might not even know it. So head on to reduce entry.ioforward/
Scott Tolinski
you are going to enjoy it. I promise you. I was about to make that same joke.
Browser permissions like webcam access use promises
Wes Bos
running, when you something goes awry. Right? That that database item didn't save correctly.
Wes Bos
and you can continue on with your with your life. So promises have 2 ideas here is that when you when you create a promise, I think await much better. The only time like I'll mix and match them is often with the fetch.
Wes Bos
from that eventually, you get the option to resolve that promise or reject that promise.
Scott Tolinski
requesting the user's permissions for things, like co webcam. Right? The reason why these have to be returned as promises because you're, again, you're waiting for something to come back from the user's computer, whether that is prompting them to do the permissions acceptance or whatever.
Wes Bos
you Mhmm. But Promise Scott with resolvers is another way to create a promise, methods,
Wes Bos
wanna
Promises help handle asynchronous actions like network requests
Scott Tolinski
with the first
Scott Tolinski
What's the deal with promises? So I think this will be a really great episode. And in this episode, and specifically and then finally gets called no matter what. We'll then we'll talk about those more in a second. So, next step is creating promises. So how do you create your own promise? Oftentimes, we're consuming promises. Right? We're using a a dot then. We're using a async await. We're we're not necessarily writing them, but you can write your own promises
Scott Tolinski
why they're a big Deno, what makes them interesting, how is it different than something like a callback function,
Wes Bos
You get something right away, but a promise is sort of an IOU, it's very hard to actually write code these days I'm gonna resolve once it's actually finished. So what what do you use, Scott, in in most cases? Do you default to sync await? insert that takes 2 seconds, then all of a sudden you're blocking any requests that are coming in for 2 seconds, and that's that's sort of a bad day.
Scott Tolinski
question.
Wes Bos
completion of some data, and that's different than a regular error handling strategies.
Scott Tolinski
yeah. We're getting into promises 101, creating and waiting on promises. So I think we can start this off
Wes Bos
What is a promise, Wes? A promise in JavaScript is an object that represents the eventual So I in most cases, I would say most people use buckle up for the next 3 weeks. We got all kinds of I promise working with promises and architecting him in flow control and all that. So this is going to be the next 3 Mondays are going to be all hasty treats and
Wes Bos
variable or a function return in JavaScript because, a sync.