JavaScript Callbacks, Promises, and Async / Await Explained

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey welcome back in this video we're going to learn how to let one operation in javascript complete before you move on to the next one throughout the video you'll see me working in different code pens you'll find links to those in the description so you can work through them and follow along with me essentially the first codepen link uses old maybe you could call it outdated or traditional callbacks and then the second link the second code pen uses promises anyways when you open the code pen up the javascript column might look empty at first but if you scroll down to the very bottom you'll see that i've already created functions called get cats get dogs get birds in super secret order the idea here is that nine times out of ten in the real world you won't need to create your own promise as much as you'll just need to know how to leverage or use a promise that a library or package or framework is offering you so throughout the video we're just going to be leveraging these get cats and get dogs functions that's just something to be aware of so make sure that you're actually in the code pen so you have access to that code one last thing before we jump into the action for this video and that is that this video is sponsored by me if you enjoy this video you might enjoy one of my premium full-length courses available on udemy in the description for this video you'll find a link to this page i'm showing right now with super discounted coupon codes for all of my premium courses having said that let's jump into the actual lesson of this video okay so this first part of the video is sort of a history lesson it's about callbacks and callbacks are not the newest coolest most elegant way of doing things however even if you yourself never write callbacks you'll still inevitably run into a project that you inherit or a library or framework or package or api that does use callbacks so it's good to be familiar with them let's review them and let's also see why they are less than ideal why they can be super frustrating to work with and why we needed a more modern alternative in the first place in other words let's begin by looking at the problem that modern alternatives like promises and async await are solving so for the next few minutes let's discuss callbacks so some actions in javascript can happen immediately for example if i say const favorite number and i set that to two plus two javascript can complete this action in one nanosecond right so then if the line right below that you tried to log it to the console or really just use it in any fashion that would be fine that would work perfectly however other actions do not complete instantaneously so if i said const cats equals and then i called the git cats function and you can use your imagination that this function goes out onto the internet and retrieves data from some other server so it needs to make a network request and obviously anytime you make a network request that can't happen immediately even on the fastest internet connection in the world that's going to at least take you know a couple of milliseconds so the point we're getting at here is if on the very next line of code you tried to use that cat's value this would not work javascript doesn't necessarily know that we would need to wait for this operation to complete before it moves on and parses or executes the next line of code so the whole point of this video the point of callbacks the point of promises the point of async await is how do we deal with this situation where we need to do something and we have no idea exactly how long it's going to take but we want to wait until it completes before we move on to the next step well in this first codepen example that's using callbacks because git cats is expecting a callback function we can't rely on it to return a value like this so even though we would like to write code that looks like this because it's intuitive and it's simple to look at and read we can't do this if we're going to use the callback approach instead you just call git cats and it's just sort of sitting here floating in outer space we're not storing it in a variable and then in the parentheses when we call it we give it an argument that's a function and then it's going to call that function once it's completed might take five milliseconds might take 5000 milliseconds but once it actually completes and it calls that function it's going to pass the data we're interested in into that function in other words in these parentheses you would say function parentheses curly brackets and then in the parentheses for this function we would include a parameter now you could call it anything x animals results why don't we call it cats because i think we can guess that that's what git cats is going to give us so eventually once git cats has finished its job it's going to call this function it's going to pass the resulting data into this function so now in the body of this function we can actually access whatever we named that parameter so we could say console.log whatever you named it cats and if we check the console perfect we see an array with three items meowzalot pers loud and biscuit maker now at the moment you might look at this and think hey this isn't that bad and maybe that's true if you're just performing one action like get cats the callback approach isn't horrible however the moment you need to perform multiple actions like this and have them depend on each other or sort of sequence them that's when things become a nightmare so for example let's look at the task up here that i've set up for us so imagine we're supposed to retrieve the cats the dogs and the birds right so each one will return an array with three animal names and then we want to combine those into an overall array and then we want to pass that array of nine animals into super secret order and then it will sort or order the animal names in a particular order and give that back to us and you can use your imagination that this super secret order function has complex logic and needs to run on a server somewhere maybe it's looking up all sorts of data of its own for its sorting algorithm in other words imagine that it also requires a network request so we don't know how long it would take so this is where things with callbacks get very ugly very quickly so we've gotten the cats now we need to get the dogs so here's what you would do we can get rid of this console.log cats but we're still within this body of the function now within the body of this function here we know that we have access to cats so then we would just want to also get access to dogs so we could call get dogs parentheses to call it now you remember you give that a call back function so function parentheses curly brackets within the parentheses we'd include a parameter let's call it dogs now inside the body of this function we could log dogs to the console but we're still not done we want to retrieve the birds so another level nested deep we'd say get birds parentheses function parentheses curly brackets birds okay now finally now that we're three layers nested deep we could combine cats birds and dogs and then pass that into the super secret order function so i'd probably just say const all animals equals cats and then i would just concatenate on dogs and birds so we could test this out we could say console.log all animals check the console cool so i have an overall array with nine animal names so now that's what we would want to pass into this super secret order function so right here i would just call super secret order when we call it within these parentheses we're going to give it two arguments so first you give it the list of items that you want to sort so we named it all animals and then the second argument is a function that you want to run once the super secret sorting operation has finally completed so we give this a callback function parentheses curly brackets within the parentheses we need to make up a parameter let's call it maybe sorted names and now within the body of this function now that we're 50 billion layers nested deep we can finally log to the console sorted names check it out perfect there's all nine names now yes if you look closely all it did was order them alphabetically and you wouldn't actually need a network request to sort something alphabetically but we were just using our imagination that we needed some sort of complex you know server-side logic to sort the items for us the point here is that this type of code is so messy that if we can avoid this we absolutely want to this is difficult to look at and immediately understand what's going on it's way too many layers nested deep so it's unmanageable not to mention the way that this is currently set up is super super slow let me explain it has to do with the ordering of our events or sort of which ones depend on which other ones in other words when it comes to calling super secret order yes we do want to wait for all of the get animal functions to actually complete before we run that right so this depends on these ones being completed however if we forget about the super secret order and we just think about the three animal functions they don't need to depend on each other the ordering of which one finishes first does not matter so with this current setup we're needlessly waiting we're wasting time because we're waiting until get cats finishes and it might take up to a full second or two and then only then are we letting the get dogs request begin and then it might take a full second or two and then only once it completes are we actually beginning the bird's request so instead what we would want to do is start up all three of these requests at the same time and then we don't care the order in which they finish but just once all three of them have finished then we would want to run this now unfortunately javascript doesn't have any built-in way of managing callback functions like that so you and i would need to take matters into our own hands and get a bit creative so for example maybe i would do something like this let me start over i would create an overall variable and maybe call it all animals and set it to just equal an empty array and then right below that i'd create a function i'll just name it maybe our logic and i'd have an if statement the condition would be if all animals dot length so if this array contains three items right cats birds and dogs so only if we have all of the items that we're interested in only then are we ready to call the super secret order before i fill out the code that will go here let me show you how i would actually use this array in this function so below this i would obviously get cats we know that we give that a function to make this copy and pasteable i'll just say the parameter can be called x and then within the body of this function i would just say all animals and i would push onto it the array of cats and then still within this same function i would just call our logic so now i would just copy and paste this for dogs and birds so literally just duplicate it call get dogs paste it in again call get birds so the idea here is all three of our requests are going to start at the same time yes we've listed cats first but when javascript runs through our code there's nothing here that tells it to wait before moving on to this next line of code now when you're dealing with network requests there's no guarantee that the one you call first will finish first so we have no idea the order in which these three are going to finish and that's fine the order in which they finish doesn't matter but what does matter and this is the whole reason we created our babysitter our logic function really the job of this function is just to keep track and make sure that all of them have finished so when each request finishes we're calling this reusable our logic function so each time it runs we're just saying hey have all three of them finished does this array actually contain three items in it now if it does we're finally ready to move on to the next step so then within this if block let's create one flat array with all nine items so const all names are all equals all animals first item in the array and then i would just concatenate on all animals the second item in the array and all animals the third item in the array cool so now this is what we would pass into super secret order so super secret order you give it two arguments so the first is all and then the second is a callback function so let's have a parameter let's call it sorted names and then finally we could say console.log sorted names now if we check the console you might see a bunch of error messages in codepen because it's trying to run your code anytime you stop typing for a little bit and obviously when your code is halfway typed in it's not going to work so you might need to just save your progress and then completely reload the codepen page anyways the point here is that our code is working only it's a lot faster than it was a few moments ago because the dog's request isn't having to wait for the cat request and the bird request isn't having to wait for the dog request so this is what we want however at what cost i mean this code is hideous we shouldn't need to use this much brain power and this much typing to accomplish something this simple so at this point the history lesson of the video is over i think we've established that using callbacks like this is terrible for a long time this was our only option in javascript so we did things this way because we had no choice however in the modern world there is something called a promise that solves both of these problems so number one it solves the ugly code indentation problem and number two it solves the letting multiple requests start at the same time and if you don't care about the order letting them all finish before moving on to something else it solves all of these problems and more so right now let's jump into the next chapter and learn about promises okay so you can see i'm in a new different code pen now and we're working with promises so we have the exact same example task there are functions called get cats dogs and birds and our goal is to combine all of them and then pass that into super secret order only this time these functions do not expect a callback function instead these functions return promises what in the world does that mean well let me show you so down here if we use the get cats function we call the git cats function it's going to return a promise so basically at the end of this line right whatever this function returns we are now working with what it returned which is a promise so whenever you have a promise it has a method that you can call of then the idea here is that we don't know how long the get cats operation is going to take to complete or resolve but whenever it does finish then is going to call a function that we give it so in these parentheses you could just give it a function when then calls our function it's going to pass into it the results of whatever the promise resolved with so in these parentheses we just say cats or make up some parameter name and then we could console log cats cool now at first glance you might think how is this any better than using callbacks because at first it looks very similar right we're still having to give it a function and it looks a little bit indented however what if we wanted to chain on another action so for example we wouldn't actually need the get dogs to wait until git cats finishes before it begins but just for a quick example pretend that we did want to wait for cats before we run dogs i want to show you how you could chain on another promise so for example we've already called dot then on this first promise wouldn't it be cool if at the very end of this line of code here if we could just call dot then again well we can so all we need to do within this function is just return another promise so if we say return get dogs right that's going to return a promise and now that's what this overall function is returning so in other words at the end of this line of code we're dealing with a promise a new promise once again and on that you can just call dot then and then the process just repeats so we give that a function give it a parameter and then we could log that to the console check it out cool there are the three dog names so the idea with promises is that remember with callbacks you keep nesting in another layer deep another layer deep well with promises you're always just staying that one level deep so you could chain on as many promises as you want right by just calling dot then dot then dot then so this is already at least a little bit better than callbacks because we're always just staying one level nested instead of going infinitely deeper however let me start over because right now i want to show you one of the biggest reasons why i like promises so in reality we don't need dogs to wait until cats finishes and we don't need birds to wait until dogs have finished so remember with call backs we had to get creative and create our own babysitter function that made sure that all of them had finished well with promises the browser or javascript itself can babysit them and make sure that they've all finished before moving on to something else we can just say uppercase promise right this is something that exists in the javascript language itself and then it has a method called all now in these parentheses we give it an array of promises so i'm going to give it get cats comma get dogs whoops you would actually want to call the function right because that's what returns the promise so get cats get dogs call it get birds and call it and actually you might be wondering why can't we just give it a promise directly why are we always calling a function that returns a promise well if you scroll down to the very bottom of this code you can see the example promises that i've created to sort of simulate a network request and the reason that when you're working with an api or a library that you always call a function that returns a promise instead of just working with a promise directly is because as soon as the browser or node sees a promise it's going to try to start resolving or executing it immediately however if you're only creating a promise within a function definition obviously that's not going to exist until you actually call the function so technically if you wanted all your promises to begin working as soon as the script loads up you wouldn't need to wrap them in a function like this but nine times out of ten when you're calling a promise you're usually doing it in response to something right like the user clicked on a button or some sort of request is coming through on a server in other words you want to control when the promise begins working so that was just a quick tangent that's why usually you'll call a function that returns a promise instead of just working with a promise directly anyways here we have the situation where we don't care which order these three operations finish in we just want to wait for all of them to finish before moving on to the next step so we can use uppercasepromise.all at the end of this line we can call dot then within then you give it a function in these parentheses we can make up a parameter name why don't we just call it results and now the question becomes well what exactly is results well we gave this an array of three promises so this is going to match what we gave it in other words it's going to be an array with three items and it's going to be first whatever this promise resolved then whatever this one resolved whatever this one resolved so what do we want to do within our function here let's concatenate all three of the animal names together and then we would want to call the super secret order and give it all nine of the names so i'd probably just create a variable and call it all animals and set that to equal and then i'd look in results for the first item in the array right that's whatever get cats resolved with and then i would just concatenate on that whatever the dog's resolved with so that would be results look inside it for the second item in the array still in these parentheses just comma we want to concatenate on something else results look inside it for the final item in the array cool so now we have this list with all nine of the animal names we want to pass that in to super secret order but remember we're imagining that the super secret order takes time to finish its super advanced sorting algorithm some sort of server operation that takes time so within this function we can just return another promise right and then we could call dot then right here so we would just return another promise we can return super secret order this will return a promise in these parentheses we want to give it the items that we want to sort so that would just be all animals so now the fact that this overall function that i'm selecting the fact that it returns another promise means that at this overall end of our line of code we could just call dot then so now we're waiting for this promise to actually resolve so then we would just give it a function when it finally finishes this function will run we can name our parameter whatever we want let's call it sorted names and then we could log that to the console sorted names if i check out the console cool there's the array with all nine items and they have been sorted now yes we could clean this code up a little bit further by using es6 arrow functions instead of actually saying function right and this entire bit of code could sit on a single line if you used es6 arrow functions but i'll let you in on a little secret even if you did that this code is still not going to be a perfect 10 out of 10 in terms of readability in terms of looking at it and immediately understanding it because we're still in this awkward situation of having to spell out anonymous functions and passing in parameters and even though we're not nesting multiple layers deep we're still having to awkwardly chain on dot then dot then so even though the underlying promise technology is amazing right and being able to let multiple requests start at once if we don't care about the order in which they finish even though that is great from a technology standpoint this promise syntax and the way that we work with it is not the best it leaves a lot to be desired so for the final chapter in this video now we're going to talk about something called async await now here's the cool part we don't even need to jump into a different code pen so i'm just going to delete these few lines of code here i'm starting fresh but i'm in the exact same code pen i want to stress that point because async await really at the end of the day isn't any different than promises it's still directly using promises it's just a different syntax it's just an alternative cleaner more intuitive syntax of working with promises but it's the same underlying technology before we get started i want to bring this full circle back to the very very beginning of this video remember when i had a little bit of code that said you know a variable a favorite number and it equaled two plus two and then on the next line we could just log that to the console ultimately this is great code this is the type of code we want to be writing you can look at this and you immediately understand what's going on you performed an operation and then on the very next line of code you're not indented it's not within some sort of callback function it's just simply the next line of code you can use what you just created this is very intuitive and it's easy to make sense of well we can write code like this if we use async weight so check this out imagine if we wanted to say const cats equals and then just call our git cat's function and then imagine if on the very next line we just wanted to log out the results of that well this literal code on itself won't work but wouldn't it be cool if before we call git cats here if we could just magically say await get cats and then javascript somehow knew to wait for this line to finish before moving on to this line well we're just one step away from having this work so in modern javascript you can use a weight like this but in order to use it you need to be within an asynchronous function so for example if i just cut these two lines into my clipboard and then i create an asynchronous function i'll name it go you could name it anything right but you're just creating a function definition and then on the line right below that just call the function that you created and you can see just like you would normally create a function but before the word function you include async so now that we have an asynchronous function if i paste this code back in we can use this magical word of awake because we're inside an async function and believe it or not this code works even though it looks like it's too simple to work it still works code ben got a little bit confused because in the middle of typing it tried to run my code so i just saved my progress and actually reloaded but you can see it works perfectly so what does a weight do well we use a weight when we want to wait for a promise to finish i don't know about you but this syntax looks a hundred times cleaner than the dot then syntax this is why this has become the industry standard way of working with promises in javascript you await a promise and now javascript will not move on to the next line of code until this actually finishes so it's a common practice you use this and then whatever this resolves with well you can just store that in a variable and then you can use it in the next line let's actually work through the whole example of combining all nine of the names and then sorting them so check this out within my go function because dogs doesn't need to wait for cats and birds doesn't need to wait for dogs we would want to run all three of those promises at once so i would say const and we'll circle back to this in just a moment but for now i'm going to say x equals and then i would await uppercase promise.all so remember this in these parentheses you give it an array and you can give it as many promises as you want and all of them can run at the same time it doesn't matter the order in which they finish we're just waiting for all of them to finish so i would say get cats comma get dogs comma get birds now let's circle back to this x so we know that when this actually finally finishes it's going to return an array with three items in it so we can just use modern javascript destructuring instead of an x here for the variable name let's include an array right square brackets and we're just destructuring the array that it's going to return so we know the first item will be the cats we know the second item will be the dogs we know the third item will be the birds so now on the next line of code i mean it doesn't get much better than this we can now use the data we've given them very intuitive names we're not nested inside a callback this is great so now we would just want to concatenate or squish all of them together into one array so i would just say const all animals equals cats and then concatenate on dogs and birds or you don't even need to save this into a variable you could literally just use this on the next line of code but that's what we would want to give to super secret order so i would say const sorted names equals and then i want to await the super secret order right that's going to return a promise i don't know how long it's going to take but i want to wait until it actually finishes when they call this you give it the animals that you want to sort so i'll give that all animals for cleaner code you could literally just include this within these parentheses here but the idea is that now on the next line of code once this actually finishes only then will we move on to this line so then we'd be ready to log sorted names to the console so if i check the console perfect all nine names in the super secret order yes we've already done this two times in the video but this time our code is very readable you could come back to this code a year or two in the future and you could look at it and immediately understand what's going on here's a quick tip if you really don't want to have to create a named function and then call that named function right just to have an asynchronous function you could use an immediately invoked function expression to do that you don't need to name your function so i can get rid of the name of this function so it's just an async anonymous function we don't need to call the function there is no function named go any longer instead you would wrap the entirety of this function in parentheses so open parentheses here and then closing parentheses here and then directly following that just a pair of parentheses to call the function that just came right before it so this is called an iffy or an iife short for an immediately invoked function expression but if we check the console you can see it's working just fine essentially this lets you use a weight because you're still within an async function okay now there is one final thing i want to talk about before we bring this video to a close so we've seen that async await isn't a new technology it's just a different syntax for working with promises so remember when we first learned about promises we used the dot then syntax to work with a promise here we're mixing and matching we're using the async await syntax to work with promises right get cats get dogs get birds return promises but you could flip it the other direction i'm not sure why you would but you could use the dot then syntax to await an asynchronous function if that didn't make sense right now that's okay and this really isn't something you would do in the real world necessarily but i want to take the time to walk through this example so that you really understand that async await is not its own new thing it's just a different way of working with promises but hang in there with me and i actually want you to do this with me so i'm going to delete this example code if you want to comment it out or save it somewhere else you can but i'm getting rid of it and now in the real world nine times out of ten you won't be creating the promises you're just leveraging the promises that some sort of library or api is providing for you but maybe sometimes you will want to create your own promise so if you scroll down towards the very bottom of this code pen here is the git cats promise that i've created it's simulating a network request and here we see the actual word you know uppercase promise so clearly this is using the promise syntax so this is using the promise syntax and we've seen how you can leverage it using both dot then and async await however what if this wasn't using the promise syntax what if this was just an asynchronous function let me explain so let's just entirely delete the git cat's function definition so we're starting fresh and let's say async function named git cats and we know that in a function you can return a value right so if we return just an array of names right let's say meowzalot jr comma pers loud let's just have two well this isn't just a standard function that's returning a value it's an asynchronous function that's returning a value and behind the scenes javascript is going to turn this asynchronous function into a promise and the value that you return is the same thing as the value that a promise would resolve now without any sort of delay like simulating a delay of a network request this isn't going to be very impressive so for example if i just paste this code in if you want to pause the video and type this in you can but essentially i've just created a promise called delay and it's just going to wait a random amount from somewhere between one millisecond up to a second but the idea is in our get cats async function maybe before we return our value of two names imagine if we wanted to await a delay of some sort right just to prove that this isn't a typical function that can you know in the span of one millisecond return a value this is an asynchronous operation that's gonna have a delay or take some time okay but the idea is we've named this function git cats however javascript turns this into a promise so now we can leverage it or actually use it just as if it was a promise so check this out back up at the very top of our code we can use either the dot then syntax or the async await syntax not sure why you'd want to use the dot then syntax but we could say git cats call that that returns a promise say dot then give that a function uh we could name this whatever you want cats and then we could say console.log cats check the console meow's a lot junior and per is loud so even though we defined git cats as an async function it's the same thing async await is just a different way of working with promises so we're leveraging this the exact same way using the dot then syntax for promises or if you wanted to use async await you could so if we had async function named go and then we called go but then inside the asynchronous function if we said const cats equals await get cats and then right below that tried to log it cool we see that works as well so if that didn't make perfect sense i realized i moved very quickly but the picture that i'm trying to get across to you is that async await is just a different way of working with promises it's nothing new it's just syntactical sugar so if you understand one you basically understand the other it's just a matter of practicing and getting familiar with both having said that at the end of the day async await this syntax that we see here this has definitely become the industry standard way of working with asynchronous operations in javascript before we bring the video to a close i do want to briefly mention error handling so if you're using the async weight syntax a nice way of handling errors is just to wrap things in try catch blocks so for example i'll temporarily cut that into my clipboard and you just set up a try block and then right below that you can have a catch block when you call catch it's nice to have parentheses error so you can actually look at this specific error but you include the code that you want to run in your try block in the catch block you can do whatever you want you could use the error that gets passed into it or you could just log a message that says please try again later right you can do whatever you need to do but we see that we don't see that error message because the code is working perfectly however if we go back down into our git cat's function definition so we have an asynchronous function that's sort of acting like a promise we're leveraging it like a promise well in an actual promise it uses the terms of resolve and reject right so when something happens successfully instead of returning a value in an actual promise you resolve the value or if you ran into an error you could reject with an error well in an asynchronous function when you return a value that's the same thing as resolving if you wanted to reject with an error you could just throw a new error and let's say the sky is blue this is bad so if we check our terminal now we see the please try again later message from when we were actually leveraging things up here or if we wanted the message that came from the asynchronous function you could actually just log the error message that's being passed into it so now we see that message this guy is blue this is bad and remember if you wanted to use the dot then syntax instead of async weight in addition to dot then you can include a dot catch at the very end and that's how you handle errors from that direction i know we covered a lot of ground in this video and maybe everything didn't make perfect sense but don't worry i mean this is one of the most complex and difficult to understand concepts in all of javascript this is one of those topics you might need to watch this video a second time or you know go search on youtube for a different tutorial from another channel but in time i hope these concepts start to make sense for you i hope this video was helpful and that you feel like you learned something thank you so much for watching and stay tuned for more web development tutorials [Music] you
Info
Channel: LearnWebCode
Views: 27,868
Rating: undefined out of 5
Keywords:
Id: JRNToFh3hxU
Channel Id: undefined
Length: 38min 54sec (2334 seconds)
Published: Mon Aug 23 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.