JavaScript Promises -- Tutorial for Beginners

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
promises promises promises empty promises broken promises fulfilled promises JavaScript promises JavaScript promises a modern feature that in many ways has revolutionized the way we write asynchronous code or code in general this is episode 12 of a 10 part series called 10 things JavaScript developers should know but probably don't this is the last video ever that you will have to watch on promises I promise you okay okay no worries hold on hold on stop stop no more no more promise jokes okay this is it I'm not gonna do it anymore I already did it in episode 11. that's it no more I promise [Music] in the last episode I showed you the difference between synchronous and asynchronous code we also touched on callback functions as our first attempt to write asynchronous code we also touched on callback hell so if you haven't watched that go watch it somewhere up here in this episode I'm going to show you how promises can help us write better asynchronous code we'll take an Asic example and convert it into promises I'll show you how to create promises and how to use promises to very different things and along the way hopefully you'll see why you should be using promises to begin with using my beloved the Y method we'll also talk about the different phases of a promise how to handle errors and finally how to chain multiple promises together so buckle up kids this is going to be an information heavy episode as a quick reminder synchronous code blocks the execution of any line that comes after it asynchronous code does not if I have two functions here that take five seconds to complete one synchronous and the other one is asynchronous when I console log hello after each of them I won't see the log after the synchronous code for five seconds whereas I'll see the log immediately after the asynchronous function that's a slight oversimplification but that's basically the difference now obviously we don't want to be blocked right slow equals bad we want our code to be to run smooth and fast let me show you some real code because it's important to understand the difference before we move forward now I already wrote two functions here that you can't see and it doesn't matter what's inside them one is called sync Funk short for synchronous function and another one that's called async Funk async funk you up async funk you up you know a little bit of Bruno Mars yeah no just me okay to the browser alright so I'm gonna call this sync Funk first and do a console log right after uh let's see how long it takes it's a little bit slow you see the the console log itself is getting blocked and we're not seeing the log here anywhere uh there we go and it took what 3 500 milliseconds and the hello showed up whereas if I call the async function you can see immediately after zero milliseconds my hello appeared right so the async function doesn't block anything it it just goes off on its own the app moves on and no matter how long the function takes to finish its job it never affects the timing of our log a sync funk you up async funk you up so if async is so awesome and it's non-blocking and it's so great and we should always be using it that potentially creates a small little problem for us now what happens if I need to follow the async process and do something after the async is done because with the sync function right with synchronous code I know when the function finished running because it blocked everything else whereas with async I may not know exactly when that function finish doing its thing well can you give me an example sure I can Craig a good example is if I need to make a call to a backend API in order to fetch some data like today's weather for example if I want to show that on the screen I have to one call the API to wait for the data to come back three when the data comes back I receive the data and four display the data on the screen I need to wait for the data to come back but I don't know how long it's going to take it depends on my Wi-Fi connection my device my other servers there's just so many other things that are in play here it's an unpredictable amount of time of weight in those cases I can't do this because weather will be well undefined why because get weather is asynchronous so the law log is gonna run before the value of weather is set actually that's not true the value of weather is set to undefined because the get weather function does return something but it returns undefined but that was the rule we saw before right the code doesn't wait for any asynchronous operations and that's the advantage of async code right that it's non-blocking so if get weather was synchronous right it would return the value like a like a string like this it would work right I would get the sunny value back and assigned to my weather variable but I have to make a round trip to the back end and ask the weather API now this code returns undefined I'm going to represent the back end call with a set timeout throughout this whole video instead just to make things you know a little simpler for now but I will come back towards the end of the video and replace it with a real back end call using the fetch API so the issue is our function no longer returns a string okay actually returns undefined like I said but the real issue here is the value of weather needs to be set before I can do anything meaningful with it whether it's logging it or doing something more interesting like displaying it on this on the screen now one way to fix this would be to set the value of weather inside the get weather function however this is pretty terrible why because to do anything meaningful with the weather data I have to do it inside the get weather function so if I need to add it to the screen I have to go inside that function and do it there that's awful because get weather now does more than just getting the weather it changes the value of weather which is a side effect if you know what that means not good but even worse it does dumb manipulation and that's just way too much for one function because that means to use that function I have to use all of it or none of it at all now one way to improve this would be to maybe set the value of weather inside another function called I don't know weather received okay A little better no more side effects but still not great because now get weather only works with the weather received AKA they are tightly coupled meaning I still can't use one without the other if I call it get weather it will eventually call weather received so I can't reuse them for any purposes a slightly better version of that would be to decouple them and send the weather received function into get weather as a callback function we talked about this in episode in the last episode so this way get weather doesn't know anything about weather received and it doesn't even care right it doesn't care what happens after that it just knows that there is a function coming in as a parameter and I'll call it when I'm done with my thing now we've decoupled the fetching logic from the Dom manipulation logic which is great it makes our code a lot more reusable I can pass different functions to get weather as a callback and vice versa I can have different functions with different values call weather received and so both of our functions just became a lot more useful and reusable so here's an example of a different callback for example right say if I want to display an icon based on the weather forecast right in this case I can pass a different callback into get weather and it still works so great this is a callback solution that we already talked about and which is fine so now we want to take this example and make it better using promises if you think about what a promise is in real life when someone makes a promise to you there are always two people involved the person who makes the promise and the person who the promise was made to the same thing happens when working with promises in code there are always two pieces involved the maker and the receiver the maker is a function that creates a promise object and returns it the receiver is the part of your code and could be a function or not that calls the maker and receives the promise and does something with it these are names I just made up so you can call them whatever you want but the point is that there are two parts to any promise one that makes it one that receives and uses it the maker is an asynchronous function so let's focus on that first so here's the same get weather function as before instead of a regular value like a string or something it creates a promise object and returns it so new promise and the idea here is because the async process takes an unknown amount of time the function needs to return something immediately all functions need to return something because otherwise it will just return undefined so instead of returning the actual data since we don't have it yet it Returns the promise of some data it says hey I know you want the weather data I don't have it right now I need to go get it but in the meantime here is a promise object that I will fulfill as soon as I have the actual data that way you know the data is coming soon it's like a train ticket in real life right when you buy a train ticket you don't get the train ride right away but you get a promise of a ride in form of a ticket but that ticket will eventually turn into a train ride so that's what a promise object is it's an immediate object that you can receive right away that indicates that there's more to come the promise object takes a function where you can add actual async logic so this is really the meat of your code right this could be your back end call it could be your pizza making from last episode or waiting for the train or however you want to think about it the real bulk of the async logic goes in inside this function also this function itself takes two parameters uh one that you can call if the promise is successfully fulfilled say the weather data came back from the API and it's called resolve so you can call that and the other if the promise fails say you couldn't reach the API or your Wi-Fi went down or for whatever reason you couldn't fulfill your promise that's the one that you call and it's called reject we'll cover those in a second but let's take a minute and talk about the different phases of a promise when you first create and return a promise object by default it's in a pending state it means we're waiting when you call resolve or reject it's no longer pending it gets well resolved or rejected so these are the three states that a promise can have pending which means we're waiting fulfilled or resolved which means it was successful and rejected which means it's done but it couldn't accomplish what we expected it to the last two can also be referred to as settled sometimes but basically you get what I mean so don't worry we'll see examples of each in a minute so this was a little bit about the promise maker let's put the maker on the side for a second and talk about the promise receiver hold on come coffee simply so the receiver so that would be wherever we call our async function from the difference here with a callback is we normally pass the Callback into our function right but with promises we don't do that instead we get the promise object back right that's what the promise maker returns so let's assign it to a variable and see what we can do with it and how to use it to the browser all right so let me clean up all of this and let's do function get weather right and I will return a new promise promises promises promises and we said it takes a function itself that has two parameters resolved and reject and what I'm going to do is I am going to create const promise equals get with uh let me call that let's log and see what the promise object does boom it's pending hmm nice we talked about that right it's the waiting part of the async process when you first create a promise like I said by default it's in pending and the reason why it never resolves is because we haven't called uh resolve or rejected yet so it gets stuck in the pending State and that's like our train ticket we haven't used it yet the train hasn't showed up yet but you do have the ticket which is right here this promise object so this guy has a bunch of methods on it so if I pre dot I don't know if you can see this but we have catch finally then the one we're interested in right now is then which is called when the promise resolves successfully so we can add this to our uh it takes a function we can add this to our object and say boom function data so it receives some data and and I'll show you what I mean in a second and that's console.log our data so that's now let's go back to our promise Creator and do let's call resolve and send in Shani and boom look at that my console log now receives sunny it's exactly what I passed into the resolve function and it works like magic so interesting so it seems like the resolve right here is a just a reference to the function passed into then and it is if you're thinking that nice job actually a then block like this um this code right here can take two different parameters one is this function so I'm gonna uh re-shuffle these things so I can actually have another function as the second parameter which will take another data and let's do that console.log uh you know what I'm gonna make this super obvious for us first param I want to show you exactly what's going on so you don't get confused with the data and this is also data so I say second param right so why what is so important why is it necessary was the second parameter necessary what is that one well that gets called if I instead of resolving do a reject second parameter gets called so now you might think wait a minute this is already a lot uglier than callbacks and a lot more code and it's a lot longer so why do we like this again good question Oli well for one thing this isn't exactly how we write them so to start with we don't actually need this promise variable here I can just go directly call the function and do my DOT then so the same result happens here right and also what I can do is I can take these functions and give them their own name the functions I can say function on suck on success um let's do that and data and I can create another one for on error and so inside my then I can say on success and on error get rid of all this uh I don't need that so let's just clean up a little bit then for this would be error let's actually let's rename these error and error and success maybe it takes the data I can say success and error can say hey I received an error and over here I can change this error boom so if I decide to reject it if I if I choose to call the reject it actually goes straight into the on error and if I call resolve it will go into my success this is a lot nicer right and what makes it even nicer is that we can we can start chaining promises to each other if I have a sequential number of things that need to happen one after another I can write it this way so let's say I get the weather and based on the weather I need to get like an icon get whether weather icon and let's say this function takes a value of weather and actually I need to you know what I'm going to do this a timeout because right now it's not asynchronous and I want to make it absolutely clear what's going on here so let me add this after 100 milliseconds so we don't have to wait too long so Sunny that's great so get weather icon so what I mean by chaining is that I can call get weather and then I can call get weather icon and let's say get whether icon does the same thing it returns a promise but instead of uh doing the exact same thing I can I'm gonna write a switch statement here that says whatever this nice this weather that comes through is based on that uh switch case uh if the case is sunny I'm going to return because if you don't know now you know I'm going to resolve uh let me bring up my emoji picker uh what do we want we want Sun let's do this sun with the face kind of creepy but that's fine I can resolve that and then I can oh it's a string and then break if it's cloudy and you'll see I'm gonna actually eventually use the use the real data use my actual data from today from right this moment and we'll see it's going to be really cool and if it's rainy I'm going to pass rain to my resolve don't look at don't judge my Emojis okay what I've used in the past let's give it a default which I'm going to uh let's say reject oh yeah that would be cool uh reject no I confound let's do that and after a second all right so what's going on here uh let me bring these guys up a little bit cool so I call get weather get weather does what it needs to do and it resolves to Sunny it says today is a sunny day then we called get weather wait a minute we didn't call it and pass in the actual uh information don't don't I have to do this like some kind of the parameter how does it receive the weather whoops how does it receive that right well that's the beauty of the then the chaining of these uh of these promises which is whatever gets resolved right in the first one that data goes into the next function if they're chained as a parameter how awesome is that right so at that point then we say all right on success everything was successful and that's the result of the entirety of the sequence uh or if it failed for some reason so let's say I I change this to be cloudy nopes cloudy nice what about rainy boyakasha now I didn't uh cover a lot of the cases like what if it's partly cloudy partly cloudy error no icon fan found so that called the unerror now another interesting thing about all this is this chaining doesn't have to stop with two functions you can chain as many functions as you want and you can see the information will flow from one to the to the next now it may not seem obvious but there are major readability benefits to what we have here and a lot of problems with callbacks that we just don't have with the promises especially when you have multiple and hopefully lots of different steps I touched on this on episode 11 about callback hell and the Pyramid of Doom I looked it up it's not called sideways pyramid so comparing these two I'm gonna show you in my trusty animation Port comparing this the Callback hell to the Simplicity of the promise syntax when you compare those two it gets more and more obvious the more callbacks you have say I have a super long sequence of events that need to happen back to back which is is not uncommon by the way it's a very common thing that we have to do quite often in modern code it'll end up something like that Pyramid of Doom right and you can probably tell why I called it the sideway pyramid I mean that makes sense it's like a permit on its side whereas with the promise syntax it stays no more complex than this I mean the benefits should be really obvious to you you can swap out uh one layer for another in the promise implementation whereas with the Callback hell it's a lot more more involved so if you implement the promise solution modifying that code is going to be a lot easier another benefit of the promise is that there's no callback so we talked about that but there's no callback that's passed into the functions so the only thing that passes into the functions is the actual parameters they need to perform their operation nothing about handling success or error so that makes our function signatures smaller and shorter and another thing I love about promises which is related to functional signatures as well is what happens if one of my async functions fails in the Callback scenario normally what we do is you would have to send yet another parameter into the function and you call it based on whether or not you have an error with promises you don't need to do any of that remember the reject parameter that every promise gets well that's exactly what that's there for if for some reason your async function fails you can just call the reject function and on the receiver side you can handle it and that's where it gets a little bit tricky because you can handle it in two different ways you can either pass a second parameter into the den block I showed you that actually we have it here on error right you can either do that or you can have an entirely dedicated block that's called catch and you can instead of doing that you can pass the on error to your catch block which is basically a catch block is basically the like a then block that only takes one parameter instead of two and that one parameter gets called when on the Creator side reject it's called reject okay so I want to actually do this again and simplify it a little bit uh so let's say I have a function called fun one a one ton return a new Promise by the way some of you might think that I repeat myself quite a bit when I make these videos and I I type things from scratch and that might take some time I recommend this is by Design I do this because repeating these uh steps is where you end up learning the most if you don't if you just copy code from me or from stack Overflow or even from yourself eventually you're just not going to be exposed as much as you would be if went ahead and wrote the code yourself so um this time I'm going to do a little arrow function hopefully that won't cause any issues for me and I'll take the resolve and the reject I'm gonna do this set timeout set time out by the way how do you like this new code editor thing I got going on this is the first time I'm doing this and I actually like it because I don't have to log as much so if I went ahead and rejected something and I said error or let's say 404 it's it's some kind of error code right so if I do that and let's say I have another function here I can copy pasta not a big problem uh and this was function two and instead of rejecting 404 it's uh resolved right let's give it mustache man no let's do this one fake mustache okay and as before I have the unsuccess [Music] the data that comes in I'm gonna do a console log data and I'll do unfail on error and this would come in as some kind of error error code right let's play around with some names let's see what what makes the most sense and here I'm going to say error and spit out the error code so now here's here's what where we can play around with the differences between catching the error scenario inside of then versus inside a catch so I'm going to call fun one which is our function that returns a promise okay and then I can say once that's done call fun2 okay so what do I want to do after that I want to do uh then on success or catch getting to the bottom of this catch on error it's it's a similar thing to what I had before but I I just want to make these uh function names a little bit shorter if I don't have any error handlers inside my ven blocks right it will just jump straight to the catch block as soon as any function within my chain fails so this is the first one right fund one it rejected so we don't even get to function two I don't think so if I do console log function two I want to see if we even get in there function two so function two does not uh we don't even reach it I don't think so if you know better and if you think we do let me know in the comments but I don't think so whereas if this was resolved um function 2 does get called right and it gets resolved to this and blah blah blah now if I change this back to a reject and so function2 doesn't get called what would happen if I have an on error right after my function one so Function One happens and then I want to say then the six once function one is successful call function two but pass in the second parameter which is on error something slightly different happens here which is um if I change this to be success and do a string literal excess data so something interesting happened uh I have a error Handler for the first function by passing it to the then block so when that happened we actually continued and hit our unsuccess well because there was a then right after this block so if I catch it inside the then if I catch the error inside then it's not going to stop the code from running the same way the catch block did it it will actually continue going through the next then and so that actually changes the flow of data the flow of information a little bit so I haven't found a really good case to do this to catch each of those steps the the errors of each of the functions in at each level you might need to there might be a case to do that I I can't think of anything I much rather just just do a global error Handler inside the catch block and that's that's just simply if anybody within the chain errors out so I'm going to resolve good data right and then what happens function one runs then function two runs so we have that function two runs and after that on success will get called let's see what am I missing here this should be called resolve not resolved success so I rather do this and if anybody within this chain rejects it bad data it just jumps out and doesn't even go into function two and the on error function handles everything so you have a lot of control here you can you can handle each error or handle them globally or a combination or nothing at all you don't even have to catch any of the errors and finally you the last thing I want to cover here is that there is another method on the promise object which is called finally finally is yet another method that you can call and pass in another function so let me call another function in the end in the Ned in the end wow learn to type buddy console log finally we be done we be done yo will be done right uh so if I let's resolve everything resolve and resolve resolve and so and finally I'm gonna this isn't good naming I shouldn't be promoting this let don't call things like in the end on finally that might be better still not great but it's better than that so finally it's just an optional thing you can pass into your chain it's just another piece of code that runs once everything else has resolved I believe if I reject any of them uh finally will still be called so in case you want to remove any event listeners you might have set up or you want to clean up after some variables you've created something like that we don't really have to do memory management in JavaScript but in case there was something you wanted to remove you can do that in the finally block now one more thing which I promised in the beginning is to let's turn this into a real example where we actually fetch data from a real API so I've already written this before so I didn't want to type it here and and spend time so this there's a function fetch data same thing a return promise object but it actually uses the fetch API which is a native thing in every browser now almost and it calls api.weather.gov it takes my location which is 3535 can you find out where that is oh well you probably know if you follow me on Instagram then it does what the fetch API does nothing too fancy and then finally it resolves uh the data which is the forecast for uh right this moment so what I can do is I can call it fetch data then um when I'm successful I want to say display data right we don't have a display data yet but I can create it easily it's a piece of cake uh and what let's say weather is the thing that comes in console.log weather what is it partly cloudy right now it's partly cloudy where I am which totally everybody knows where that is um I don't know if I can turn this into a failure let's do a catch block uh on error or on failure I can do a function I'm gonna try to break it okay on error uh air air roller wow this is awful watching me type must be painful is it okay so on error that would happen uh let's say I wanted to do let's break it I don't know if I can break it oh no that's I shouldn't be doing that that's actually like blowing it up uh so let's reject uh what if I reject yeah partly cloudy I still pass then uh the correct data but you see how now I can uh handle both the positive and the negative scenarios so this is an actual workable or working piece of code that it's reading from a real it's fetching real data from a real API and it's using promises to handle both the positive and the negative so to simplify and to wrap up here we have three functions fun one fun two and fun three they have to be called one after another and they're all asynchronous functions so we have to wait for uh all of them one by one to finish promises makes using these functions a pleasant experience because instead of passing callbacks into each other you keep the function parameters clean and without any unnecessary stuff like area handlers and things like that instead you define your callbacks using the then block and you can handle any potential errors using the catch block and potentially optionally if you want to chain a finally block at the end to run any additional code that you might have to run at the end you can do that thing too and that's it and so those are some of the basics of promises there's more to promises than what we covered today so maybe I'll make a follow-up video at some point in the future and go deeper but it's becoming a long video so we're going to stop here I'm going to cover async awaits in the next episode we'll actually take this example from today and we'll convert it into using async awaits in episode 13. now you know what I'm gonna say right please go and practice this stuff find a public API you can probably just Google you know public apis find one that is interesting to you there's a lot of free ones and play with different configurations of promises the then and the the catch and all those different things I showed you start small and understand how to make a promise and then how to return it and how to receive it and how to use it this stuff is very important for like I said for navigating today's JavaScript environment so I hope you got some value out of this this was episode 12 of Cheers 10 things JavaScript developers should know but probably don't all right I gotta go and get some rest have fun coding and see you in episode 13 async await I can't wait [Music]
Info
Channel: ColorCode
Views: 41,112
Rating: undefined out of 5
Keywords: ColorCode, javascript inheritance and prototype chain, JavaScript, JS, ReactJS, es6, inheritance vs composition, javascript for beginners, coding for beginners, jS inheritance, js tutorial for web development, Prototypal inheritance javascript, Javascript prototype, javascript objects, Web development 2021, web dev, Async, Asynchronous, Async await, Promises, callback function javascript, js promise, async await javascript, asynchronous javascript, callbacks javascript, callback event
Id: TnhCX0KkPqs
Channel Id: undefined
Length: 37min 4sec (2224 seconds)
Published: Tue Oct 04 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.