Asynchronous Code, Callbacks & Promises -- The Modern JavaScript Bootcamp

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right welcome back we've got a big section here it includes a couple different topics by the end our main goal is to make http requests from javascript from the client or from the browser so load data from an api send a request somewhere so very important stuff that you do all the time if you make single page apps and in the projects that we build later on there's at least a couple examples where we're working with http requests in the browser but before we do that we'll talk about promises and how we use promises to manage asynchronous code and make our life easier but before we do that we're going to talk about asynchronous code or async javascript what it actually means uh and in order to do that we need to understand how javascript works behind the scenes at least we don't have to go crazy into detail but we need to understand the basics so that's where we're going to start in this video we're going to talk about something called the call stack so the call stack is a tool or a feature of javascript it's also something you see in tons of other programming languages what it does is it helps javascript keep track of where it is in your code if you have multiple functions and some of those functions may call other functions which often we have functions that call functions i call functions the call stack is the mechanism by which the javascript interpreter keeps track of its place it's how javascript knows which function is currently being run which functions are not done yet what's waiting on results or return values you can kind of think of it as this diagram here if your script with a bunch of function calls is a massive book the call stack is the bookmark or your finger that you use to figure out where you are to keep track of your current place and before we go into any more detail let's talk about the stack part i think call in call stack makes some sense it has to do with function calls which functions are being called what is or what's been called what is waiting on a result to come back the stack part has to do with a data structure in computer science called a stack a stack is a very simple data structure all you need to know is that just like a stack of books on your your desk or a stack of plates on your in your sink the last thing that you put in is going to be on top and that will be the first thing that you remove so the last thing that was added the most recently placed item in our case this apple on top will be the first thing out you don't grab from the bottom of a stack of papers you grab from the top the most recently added thing to that stack and that's important because that's how the call stack works so we're going to walk through a simple example here's what you need to know when a script has some number of function calls the very first function call that the javascript interpreter hits or reaches will be added to the call stack that function will be carried out and if there are any other function calls within that first function they will be added to the top of the call stack and that continues until one of those functions returns a value at which point it's removed from the stack it's gone and then the function that came before it will hopefully finish maybe there are some other function calls in which case those are added to the top of the stack and then removed or popped off as they complete i think this will become clear if we have an example so on the left i have a couple different functions the first one is called is right triangle it accepts three different arguments a b and c three different numbers and it should return true if a and b if you square them and add them together you get c squared a squared plus b squared equals c squared so if something is a right triangle the third value here c would be the hypotenuse these two would be the other sides i can't remember what they're called but we have two sides on a triangle and then the hypotenuse and a right triangle so nine would be three times three sixteen four times four and twenty-five five times five and that indeed would be a real right triangle 9 plus 16 does equal 25 okay so is right triangle is not a function that just returns something immediately it needs to call other functions it's going to return if the square of a plus the square of b is triple equals to the square of c so square of a needs to be called and that in turn calls multiply x times x so we pass in 3 multiply 3 times 3 which is a different function which returns two values the product of them so when the interpreter encounters the very first function call is right triangle three four five it's added to the call stack which is what i'm representing over here and we can't just get a value back immediately there are multiple function calls in here that happen first so square of a which is 3 in our case square of 3 will be the first thing to be added to the call stack which is what this slide is square of 3 does not return anything either it calls a different function multiply 3 comma 3 which i'm showing here so then multiply is added to the stack so this function has not finished running this one has not finished this one doesn't call any other functions so it returns three times three which is nine and when it returns a value it is removed from the stack the last thing in is the first thing out so then square of 3 now has a value back from multiply which was 9 so it can return that value so it's popped off now we end up with is right triangle that's the current function that is being executed it's been waiting a while because those i mean a while is relative but i had to wait for two other function calls to return so now you can kind of fill in the blank here the first part square of a square of three is nine we have a value then it moves on all right is there another function call yep there is square of 4 which is b so square of b so square is added to the top of the call stack and when i say top it's not really a top and bottom situation it's just a data structure think of it kind of like an array but much simpler but i'm just using top and bottom here to help explain visually what's going on like a stack of books so square of 4 doesn't return a value right away at least it has to call multiply 4 comma 4. so that's added to the top of the stack that does return a value x times y 4 times 4 is 16 so that pops off the stack then square of 4 now has a value for this it fills in that blank 16 which means that it's done because it returned 16 and then we fill in the blank in is right triangle we now have this done this done and then we have our triple equals square of c square of five so five is added to the call stack that doesn't return a value yet it has to figure out what multiply of five comma five is so that is the next function call added to the call stack that returns 25 which means that square now has a value so both of those are popped off and then we end up with 25 here no more function calls now just some simple math and actually the order here it probably evaluates this first anyway nine plus 16 it doesn't actually matter here we're just talking about function calls but we end up with 9 plus 16 triple equals 25 that is true so this function finally returns true at least in this case and it is popped off the stack the call stack is empty it returns true and we're done so that is a brief intro to the call stack in the next video i'll show you an example of how you can actually see it using the dev tools or at least a representation of it with your own code and you can step through it step by step all right so let's do that next okay so that was a brief intro to call stack now i'd like to show you in the chrome dev tools how you can actually take a look at the representation of the call stack and step through it one call at a time so let's do it i have some simple code here a function called make rant that i'm calling twice i'm passing in a string the rant text and then a place to append a new h1 what it does is it makes a new empty h1 then it sets the inner text to the result of a function called get rant text get rant text is going to call two different functions the first one is scream which uppercases it and adds some exclamation points then another function i call repeat yes there is a built-in string repeat these days but for this example i'm not using it i wanted a couple other functions on the stack so then it calls repeat which takes that scream the upper case version of whatever we pass in so let's say we started with go away that's our phrase we pass in it's going to call scream which will give us go away with three exclamation points and then if i call repeat which i am here get rant text repeats it eight times we end up with a string that looks like this oops eight of those then we take that and create a h1 which we've actually already created we add that as the inner text and append it to whatever element we pass in so it's just a dumb demo it's not something you probably would do but this is what we end up with over here i have two h ones i hate mayonnaise very true i hate mani so much oh my gosh i just i feel queasy even just writing the word let alone seeing it eight times here that's coming from make rant i just passed in the string and a place to append the new element and then here's the second one if you have to cough please cover your mouth it's also being appended here let's take a look at just one so it will make it a little easier when we step through the call stack so i'm going to open up the chrome dev tools and go to the sources tab and in the sources tab i'll pretend that was closed if we open up this navigator on the left side for me go to our file with the code so app.js is the name of my file whatever you named yours what we do is add in a breakpoint on the left i can actually click so if i click in here i can make some changes and play around with them but if i click on the number to the left of one of those function calls it will actually insert a breakpoint it will pause execution of our code when it encounters this so all of this code will run first if i were to add in a console.log console.log hello and refresh the page ah well i'm an idiot it goes away of course i just said that if i do a console.log here hello this will run first before we encounter that breakpoint if i look in my console we get hello notice though i don't see anything over here it says paused in debugger and i have this little alert over here that says paused on breakpoint so because i clicked there it paused if i unclick and refresh it doesn't pause anymore but if i click and i refresh the page there we go okay so let's see what we can do on the left side we have a tab or a piece called call stack this is where we'll see a representation of the call stack and if we just walk through this first on our own i'll zoom in a bit can i zoom in okay i'll close the sidebar make rant is going to be called there's no function calls aside from make rant so far so make rant will be added to the call stack then make rant itself calls document.createelement is a built-in function or method that won't appear on the call stack really but our first function we defined is get rant text so get rant text is over here that calls scream so scream will run and return something then we get to rant and that's returned we have text then repeat is called with that value so repeat is going to run so let's just play around with it i'm going to click over here on this there's also a shortcut but to make it easier for you to see when i'm actually advancing i'll just click so keep your eye here where it says call stack okay so make rant was added to the call stack it's not done executing otherwise it would be off and it can't be done it has to do some other stuff first so the first thing it did was evaluate this document.createelement then we get to this line get rant text so you'll see get rant text is now added to the call stack and if i look at any of these at any point if i click at make click on make rant you can see it's kind of hard to show here but this is the information the values that are in current in this scope of make rant so phrase is set to i hate mayonnaise that's the argument we passed in we also have element which is the body which i passed in down here and now this h1 variable is this h1 element that we created with document.createelement so then instead of getranttext we have a variable text but it's not set to anything yet if i move forward again we'll see scream added to the top of the call stack there it is so make rant started but it's not done it can't finish until get rant text comes back that can't finish until scream comes back we're in scream right now scream does not call any other functions aside from returning string.2 uppercase so you'll see if i advance again scream is up top advance and it's gone scream has been removed it finished executing in a return to value which we now have here text has value i hate mayonnaise all uppercase with three exclamation points that came from scream then next line rant the variable let rant equals repeat of text this is text that variable so repeat this eight times so repeat is going to be added that's our next function you'll see it added to the stack there it is so get ran text is still waiting make rant is still waiting on get ran text which is waiting on repeat so repeat is then going to loop i'll skip through this so we have results which is completely built at this point the loop is over we're now at return result so result is i hate mayonnaise uppercase exclamation points repeated eight times in a single string that is returned so the contents of the function don't really matter in these examples i just want you to pay attention to the call stack itself watch when things are added and when they're removed so return results repeat should be removed and there we go so now get rant text has all those function calls it has return values from them it's done and it's ready well it's not done yet but it's ready to return rant so it waited first to get scream then scream came back and it waited to get repeat then repeat return to value so now we can return that value so it's going to return and get rant text will be removed there it goes goodbye now we're back in make rant the original function call that has been waiting patiently this whole time so you can kind of see where i was going with this uh where are you this idea here of a finger in a book to keep track of where you are it's kind of the same idea maybe i don't know if that's a good analogy or not but it's it's kind of the same idea this function was originally added to the stack a while ago but it couldn't finish until a bunch of other function calls ran and this is a simple example often you'll end up with some functions that have a whole bunch of function calls which call other functions and then recursion is a whole other issue which we're not going to get into at this point but just know that this is a simple demo most of the time your apps are going to have many more functions on the call stack at any given point or they could at least so make rant is now ready to append element out of pen child there is no return statement in make rant so there we go we get to the last line it's showing me this here so make grant will be removed from the calls deck and because this element.appendchild.h1 ran we now have the text showing up our new element on the screen so i'll step through it and it's gone it's completely off the call stack which means that this function call here is done it finished that was the original starting point now the interpreter has moved on to this line and there's nothing after it it's just done and there we go we made it through so that is how you can use the dev tools to step through step by step each function call on the call stack and see what's going on and this can be useful if things are just behaving very oddly it's also a nice way if you add a breakpoint somewhere for you to just take a look at the values at any given point play around with the variables in there see see what's going on diagnose your problems but the main reason i brought it up here was just to make it clear how the call stack works this idea of the latest function call to be added to the stack that function call will be the first to be removed and you end up with this pile up of functions that are function calls that maybe are waiting on a bunch of other function calls to finish which themselves might be waiting on other function calls and eventually one of them has to finish and return something so that sort of a reverse cascade can happen the functions that we're waiting will hopefully return which continues all the way down to our original function call which was make rant so why are we talking about this why do you need to know about it well it's going to help explain and help you understand how a synchronous code works in javascript which is what we're going to tackle right now well next video right after this okay so we talked about the call stack put that aside for just a moment next we need to address a fundamental characteristic of javascript as a language javascript is a single threaded language if you don't know what that means don't worry all that it really means is that at any given point in our script whatever script is being executed javascript is running one thing at a time it's it's not multitasking it does one thing there's a really good blog post i think it's on the google one of the official google developer blogs talking about asynchronous javascript that humans are multi-threaded you know if you can fold the laundry while watching tv or talking to your friend or whatever it is but humans are single threaded in one very specific case according to this blog post which is when we sneeze no one can do anything else except sneeze so when you're sneezing that's the one thing you're focused on so back to javascript at any given point one thing is being run at a time and this has a whole bunch of implications but let me just demonstrate it first if we do something extremely simple we console.log i happen first and then a different console.log i happen second and if we alert in the middle alert either and i run this code what will we see in our console when i refresh the page well let's refresh it there we go i get the alert we open up the console oh it won't even let me open it will it well let's try it one more time i'm going to refresh we get i happen first and then hi there and it just stops this alert is blocking everything else from going on until a user finishes it or completes it at which point javascript moves on to the next line so that's a simple example but here you can tell javascript is doing one thing when it's alerting it's not continuing to console.log or if we had math after this or a different function call it's not going to move on and that seems like it could be a severe limitation if we do things that take time if we do things that aren't immediate we don't want to just have a user sit there waiting and have no other code running but as you've probably seen already we have a way around this and we'll get to that in just a moment but here's a simple example of something that we do via javascript all the time we send a request from the browser we write some javascript code asking for let's say data from a movie api that takes time it goes and sends a request to a server that server may or may not be online we may have a valid endpoint we may not but even if everything goes great it still takes time the server will respond to your request if we're looking for movies that match the query bat bat it will search through its database find the relevant information and then send a response back bates motel and batman in this case again this takes time it can be very slow so what happens to our application does it just stop and nothing else happens like what we had over here where this alert potentially takes a long time for a user to finish a user may not notice it i mean even if it's just a split second your code is just doing nothing right now is this what happens when we make a request when we are fetching data from an api when we're trying to save data to an api anytime we do some sort of single page app functionality which usually involves communicating with an api communicating with a database or a server that takes time is our app just going to sit there doing nothing and is a user just going to sit there waiting for something to happen the answer is no how does that work and why not that's what we're going to answer in the next video javascript has a couple tricks up its sleeve or rather the browser has some tricks up its sleeve to get around this single threadedness of javascript so to summarize what we saw here in javascript at any given point javascript itself is running at most one line of code so it's not multitasking it's not doing three things at once it's doing one thing at a time or nothing if it's not doing anything it's very important to understand that so that you can better understand the work around we have which we're talking about right after this okay so we established that javascript is single threaded that means it's doing one thing at a time like a human sneezing a human does one thing which is sneezing it's very very difficult to also talk while you sneeze or eat while you sneeze although i guess i have been driving and sneezed and i continued to drive but i basically just prayed that i wouldn't crash because all i could do was sneeze so javascript does one thing at a time as we mentioned in the last video a lot of the time we do things that take a lot of time that's a bad sentence commonly we do a lot of things that take time whether it's getting data from a database or an api or trying to save something or even just set a timer how how does something like a timer work in javascript so here's a simple example this is not exactly full code that would work i've made up a function called save to database but imagine we're doing something like this a user types something into a form it submits we want to grab the value from the form save it to a database and that could take a couple of seconds it could take half a second it could go really fast it could take 10 seconds and fail does this line just not run until this finishes well we have a workaround we've seen this a couple times before we've actually seen it a lot for these processes processes that take time we pass a callback function and those functions will be executed at the appropriate time after this interval has passed in the case of a set timeout but this doesn't really answer the question of how does it work or why does it work we know that this does work set timeout for three seconds will wait three seconds before running this code but how is javascript gonna know how does it set a timer for three seconds if it can only do one thing at a time that is what we're going to talk about here if we go back to this example where we had our first console.log and then the alert blocked everything else javascript is fully focused on the alert until it's gone then we move on to the next console.log why if i replace this with a set timeout pass in some function where we console.log i happen third and then an interval or a delay three seconds three thousand milliseconds why does this work seems like it shouldn't like nothing different is really happening except we're passing in some some function to be called later but based off of what i've told you it seems like this should run then javascript encounters this line which says set a timer for three seconds that should just take up javascript's full capacity to focus on anything it should just be setting a timer how can javascript keep track of three seconds and remember to do this or call this function while also moving on to this console.log remember that is printed out immediately and then three seconds later this is going to print out so if i have other code down here i could have a whole bunch of other stuff that's all going to run assuming that it doesn't take more than three seconds that will run before this doesn't seem like it should be able to work seems like javascript should have to focus entirely on keeping track of three seconds and knowing when to actually execute this but we have a workaround the trick here is that the browser does the work javascript is not the same thing as your browser javascript is a language that is implemented in your browser but the browser itself like chrome safari even internet explorer our good friend when i say good friend i mean worst enemy those browsers are written in usually c plus a different programming language and the browser itself is capable of doing certain tasks that javascript sucks at or things that take time they're handed off to the browser so javascript says here is this thing i need you to do for me the browser takes over and then when it's done it reminds javascript okay your turn again so this is a really key thing to understand javascript is not setting a timer or keeping track of how many seconds have gone by javascript is not sending a request to an api the browser actually handles it and this is something that honestly i went a long time without understanding about javascript and it's not crucial to being able to make a request or use set timeout you've already done that in this course but i think it helps a lot to understand why we use callbacks and why we get to things like promises and async functions so browsers have a set of these apis called just generally web apis and they can handle certain tasks in the background like making a request that takes time set timeout which we saw here that takes time the browser is capable of doing those things in the background so javascript is going to encounter certain lines of code like this line javascript knows how to do that then it gets to set timeout and it's going to pass it off to the browser and say please remind me after three seconds has has elapsed or hey browser you set this timer for me and when you're done give me this function back so that's why we pass a callback it just keeps plowing along it hands this off to the browser the browser is in charge of keeping time and then it reminds javascript hey here's that thing i want you to do or you wanted me to remind you of so javascript doesn't get hung up it's single thread isn't blocked by this set timeout because it's passed off to something entirely different it's passed off to the browser then that callback function in the case of set timeout when it's time when three seconds has elapsed the browser is going to take that function the one that just console.log something and put it on the call stack so this is where the call stack comes back in so let's take a closer look with some diagrams here we have similar code i think different text i print first i print second is that what i had ah okay i capitalized it here it doesn't matter so javascript is represented by this javascript logo it's going to encounter this line the interpreter sees this line it knows how to handle it console.log i print first it runs that then it gets to set timeout set timeout is something that the browser will do for us or it will do for javascript so this is my personification a browser can you set a timer for three seconds the browser says sure thing so remember this is separate from javascript this is the browser itself setting a timeout keeping track of 3000 milliseconds so then javascript is free to continue on it doesn't have anything in its call stack that has to do with set timeout instead it moves on to console.log i print second so it prints that out and there's a little time icon over here that signifies three seconds have elapsed now the browser says time's up javascript make sure you run that callback now and it places the callback this function right here i used an arrow function in this example i just used a regular function expression here it places that function back in the call stack so javascript knows oh i need to do this thing so javascript does not keep the time same thing with making a request javascript does not make the request itself the browser and its web apis handle they manage all of that and they simply tell javascript they add to the call stack when it's appropriate here's the next thing for you to do so javascript then now has a new function in the call stack and it executes it and at console.logs i print after three seconds so understanding this relationship will help a lot once we get to promises and actually making requests javascript can only do one thing at a time it's single threaded but in special cases when we are doing things like setting a timeout requesting data or adding an event listener to whatever a div an li javascript isn't going to sit there and just listen non-stop to see if something's been clicked that's handed off to the browser and the browser is in charge of deciding when to actually add a new callback or a function to the call stack for javascript to execute here's this really cool website i found that helps explain how this all works so you can type code over here if you do play around with this it's called loop it doesn't work well or it doesn't work at all if you use arrow functions or any of the newer javascript syntax so just stick to some basic stuff but here's what it does it actually slows down or it mimics the execution and what happens behind the scenes with javascript and the handoff to web apis which is what this box over here represents here's the call stack here's web apis so javascript is going to encounter this line the interpreter it can run this immediately and it will console.log hi everyone then it hit set timeout and you'll see visually that the web apis takes over and you'll see visually that the set timeout the interval or the delay is being kept track of over here for seven seconds is what this one is set to and then another set timeout this one for three seconds will also be handled over here and in the meantime javascript will move on if i add in let's do at least one more console.log console.log buy for real everyone javascript moves on to this and then when the browser the web apis over here decide or calculate that the time is is up seven seconds or three seconds they add the callback here not directly to the call stack they add it to something called the callback queue we don't have to get too far into the the weeds here but essentially this is a place where callbacks are added and javascript will draw upon this queue it's a way of it of javascript to know okay what's something that i need to do next that is coming back from the web apis okay so let's see what happens when i click save and run i'll pause first thing call stack now has one function call console.log hi everyone okay simple enough so it does that now it gets to this set timeout function that is added to the call stack but javascript realizes oh this is one of those things i can hand off to the browser so it doesn't take charge of this it hands it to web api with the web apis there you go so it doesn't run the code it doesn't run the callback ah i just broke it okay let me pause again at the right moment there we go there's a timeout that is being kept track of over here and javascript moves on to the next line which is another set timeout so the same thing happens it's added to the call stack for a moment javascript then passes it off to the web apis and says okay when when that interval or that delay is over give me that callback back and i'll execute it at the right time so we resume javascript moves on to these two console.logs there's the first one the second one they both run and then the three second timeout finished now there's only one over here the seven second one the three second one finished and it added the web api added that callback here which is supposed to console.log oink oink it added that to the callback queue which javascript will now draw upon and you'll see that it oh did i not click resume there we go those functions are then executed one at a time they both console.log and we're done so let's do it one more time just quickly i won't pause you can see the web apis take control of those timers javascript moves on it has one thread it keeps going and then it draws upon that callback queue when the web apis have placed one of those functions in the callback queue that relationship is very important to understand so let's pause and now i'll have my console open so you can just see the whole thing as they get printed so we get hi everyone then the next line which will be by everyone then buy for real everyone then that first callback the three second one is added to the queue we get oink oink and then the seven second interval or timeout finishes so we get mu okay so i'll stop here like i said this is a very fundamental part of javascript this is why we use callbacks all the time this is how we get around the fact that javascript is not a multitasker it does one thing at a time so when we pass a function as an argument as a callback function to things like set timeout which the web apis handle those functions are not called right away javascript doesn't worry about it javascript just passes it off and continues on its merry way until the web apis at some point place that function in the callback queue where javascript then draws upon and says oh okay you want me to do this thing i guess it's time so it does not do the hard work of keeping track of time it doesn't do the hard work of making a request and that's why we use callbacks so frequently for these asynchronous things these these functions that take time and i need to make that clear because now we're going to go more into async js we'll talk about how we make requests and that takes a lot of time and sometimes it sucks to write a ton of callbacks which is where promises come in so this has been setting the stage i think it's very important to do i have taught promises and async functions without really going into detail of how this works but i think this will help i hope and please leave some feedback if you think i'm just confusing you or it's not really relevant because you absolutely can learn this stuff without understanding what the web apis are and the call stack but i think it will help maybe so let me know all right i'll be quiet and next we'll move on to talking more about callbacks some of the problems with having a bunch of callbacks and how we can get around them with promises all right welcome back so we saw why callbacks are so important in javascript we pass a callback in to certain functions that the browser takes over things like set timeout set interval also when we make requests different ways making requests we haven't really covered yet the browser takes care of that and we pass in a callback but callbacks are not perfect they can get messy very quickly which is what i want to show you here i'm going to show you a way of doing something with callbacks and then we'll see how to refactor it using promises so this is finally the ramp up to promises let's write a simple function that will take a number of pixels and move our button over that number of pixels and it will do it after a delay so we could do like after a second move it after another second move it and so on so i'm going to start by selecting the button it's the only button on the page so const btn equals document.queryselector button then all we're going to do is change button dot style i'll do it with transform this time i think a couple at some point in the course i did button.style.left and top which is not really the most performant way of changing a position or moving an element around transform is better and if you're curious why i have a youtube video you can check out on it it's called the only two css properties you should animate the short story is that when you transform something it happens much later in the browser's rendering process it's much easier for the browser to move something via transform rather than changing left which causes a re-render of a lot of different things anyway so i'm just going to do this we'll move it left to right so i'll just do translate x and pass in a number like 100 pixels and let's just make sure it's moving okay so now i want to do this inside of a set timeout so it only happens after let's say one second so set timeout and then i'll pass in a function just do an arrow function here my duration will be 1000 milliseconds and i'll move this right there so now i refresh it should start on the left and then one second later it moves that works great now if i wanted to wait another second and then move again maybe 200 pixels this time or some other number i would need to nest that function call the set timeout inside of this set timeout otherwise if i just have a second set timeout i mean i guess you could do this and just keep track of the number of seconds but this is not ideal i will see an expanded version of what we're doing now where this wouldn't work but yes technically if you want this to run after one second and this to run a second later you could do 2 000 milliseconds but we're not going to do that so in here we add another set timeout same thing we add in our callback our duration let's do 1000 seconds or let's do 2000 milliseconds so 2 seconds and then the same line i'll just duplicate it and i need to change what we're translating it to let's do 200 pixels so i'll refresh a second it moves another two seconds it should move again cool and i could keep duplicating this i just have to keep nesting if i want to make sure that this is happening after this happens so we have our first set timeout for 1000 milliseconds it does this and then as soon as that happens it sets another timeout for 2000 milliseconds and then again let's just do 1000 for each of these let's translate 300 pixels this isn't so bad because it's such a short thing that we're doing but it is a lot of nesting to achieve this let's go five levels deep okay so now i have five different set timeouts all of them one second long let's go 1 2 3 400 pixels and 500 pixels let's check it out it should move across the screen 100 pixels at a time one second at a time okay so this is relatively readable it's not too bad it's kind of obnoxious to have to keep nesting them but that's not this is not as bad as it will get let's put it that way so if i want to rewrite this as a function i'm doing kind of the same thing every time if i want to make this a separate function i could call what i need to do is first define my function and come up with a reasonable name let's call this move left no move right i would just move x because then we could pass in a negative number to go the other direction we'll do element the thing that is moving so our button an amount and then a delay and then we'll do a set timeout and then in here our function we'll put the delay right here so that will be some number we pass in like 1000 and then instead of button.style.transform it will be dot style dot transform equals and then a string i'll do a string template literal translate x and then i'll put in my amount that was passed in and then follow it by pixels just like that so if i comment this out and i just call this one time move x of button let's go with 600 pixels so 600 and after two seconds let's see if it works so two seconds go by okay it does move now here's the tricky part if i want to then replicate this behavior where we could have something happen after this or after the delay immediately after we change the transform i want another set timeout it doesn't really help me if i just manually set it here what we would do instead is pass in a callback so we would write our function to accept a callback we could call it callback and then all we do is execute that callback function inside the set timeout after we do this we call the callback same idea that we have here but now what we need to do is pass in a callback so we would pass in a function i'll do an arrow function oops like this and we'll just call move x again button let's go 100 pixels this time we'll replicate the same behavior so one second another 200 pixels after one second let's just see if that works we will run into an issue with what i have here because i haven't passed in a callback so we could do something simple like if callback okay and let's see what happens it appears to work right so we did 100 pixels and then 200 pixels after a second and we could pass in yet another callback if we want to continue to change chain these so move x button let's go for 300 pixels one second and let's actually do four or five levels button and then 400 pixels a thousand milliseconds and one last one move x button 500 pixels 1 000 milliseconds no callback here we go there we go keep moving awesome okay so we wrote a function here that accepts a callback and a delay it does something after that delay inside the set timeout that delay is variable right now they're all the same and then it executes a callback if we pass one in and our callbacks are these arrow functions so this is one callback this entire thing here from here from this curly brace to this curly brace nope this curly brace to this curly brace that is the callback for this first move x so this entire thing from this yellow curly brace down to here is the first callback for move x the first time we call movex that function call those parens go all the way down right this is our initial function call and then we have our callback in there and then that itself calls move x and then that has a massive callback all this nesting it's still not that horrible because we're just doing one thing each time you can look at it it makes it clear you're doing this then this and this but here's where it's going to get trickier let's rewrite our function so that we check if the element is going to go off the screen and if it does go off the screen we can do something else maybe reverse it or just console.log or just stop we won't do anything and this is a really common pattern when we're working with asynchronous code often we'll send let's say an http request the term is request for a reason we're attempting something we're asking for a web page we may get some successful response or the server might be down we might have an invalid url your internet might be down at home or on the computer so it's a request and that request let's just say this is the name of a function to make a request oops autocomplete there that request will accept two callbacks a success callback and a failure callback so you can have two different branches if the request works out here's the code that runs if the request does not work here is the code that runs the code to handle an error for example so why don't we mimic that functionality here for move x instead of just moving no matter what let's check if we are going to move off the screen and if that's the case we won't do this we won't call the callback we won't move further we'll do something else we'll pass in a potential fallback or an error callback so i'm going to rewrite this here the logic to check if we're moving off the screen is not that important to what i'm showing you here but basically we want to get the width of the screen document.body.client with and we'll save this to a variable let's call it const boundary body boundary or something then i'll show you a new method we haven't seen before there is something called get bounding client wrecked let's test it out first in the browser so i have a button right here it's moved already i won't refresh the page if i call up that button variable and i call let me zoom in here button dot gets bounding client rect which is a method for rectangle rect get wrecked here we go it returns this object it's called a dom wrecked and a dom rectangle and it tells us information about this element so we can see its width 225 pixels 0.875 we can see uh it's right let's see 733 is that correct let's try moving it further so let's do the same thing why don't we on our last step why don't we move 600 pixels over so instead of 400 we should be 600 or instead of 500 i mean we'll go 600 so currently it's at 733.875 if we refresh and let it let it do its thing just wait here kill some time let's see what we get now for the right the right is now 833.875 and if we call move x again button will move 800 pixels and uh let's nah one second is fine no callback we wait one second now let's look at our get bounding client wrecked right is 1033 and what is our entire width right now of the body document.body.client with not height but with 1132 okay so we're close what we want to do is compare those two the right if we're going to the right at least we're just worrying about moving to the right so we'll check if the right is greater than or equal to this boundary here which we already have document.body.clientwith and that will change depending on the screen and if i have the console open so it's not just the dimensions of the screen itself we've seen this before client with is going to update okay so let's grab that variable get bounding client rect and we want dot write so let's save this const l right element right and let's rewrite our function before we go any further so that we don't have to pass in this absolute number for example 100 then 200 then 300 than 400 what if i could just say move 100 and then another 100 then another 100 and this would put us at 300 pixels to the right of the initial position we would need to update this ever so slightly so i'll just comment that out for now for amount we can keep that the same but instead of just setting translate x to be that amount we can calculate the current transform or the current position on the screen and then add to that whatever amount is passed in and use that to translate so the current amount if we want to find that is right here if we use get bounding client rect we have the let's see left is 808 and then we have a little bit of i believe it was margin or padding that added eight pixels it doesn't matter let's we're not going to be super precise i don't really care if this is going to be incredibly accurate i don't want to get too bogged down so let's use this left so whatever the left is we'll then add another 100 or 200 whatever the amount is we're trying to move i'll make a new variable i'll get the left and save that to a variable called current left then here i'll just translate x to amount plus currents left so now when i call this i hopefully can just say move 100 pixels at a time it's easier you don't have to keep track of if you've moved 100 then you want to move 200 if you want to move another 100 you have to add it together and do 300 now i can just say 100 every time or 200 every time or mix it up but i don't have to know how far we've already moved okay so translate x let's just let's see if it works refresh the page it's working it's moving 100 pixels every time okay so now we can go back to checking if we've gone too far or if we're going to go too far we have our boundary we have the current right of the element and what we want to do is check if that writes plus let's say we're moving 100 pixels if another 100 pixels to the right is going to be too far and we'll be off the screen then we don't want to move so we could write a simple conditional if element right plus the amount we're trying to move is greater than the body boundary what do we want to do why don't we start with just console.logging done and i apparently cannot type greater than old console.log done can't go whoops double quotes there cannot go that far else we need the else otherwise we'll just print this out and then run our code anyway so let's add an else we'll do the set timeout down here oh boy okay so we try and move 100 pixels every time and if it's too far like if i do the last one and try and move 500 pixels let's see we should move four times two three four oh well i'm an idiot i move the screen let's try and move a thousand pixels that should be enough for it to trigger okay so 100 100 and now we try and move a thousand perfect cannot go that far let's try it one more time and it doesn't move us any further that's it okay so that is working we now have this situation where we don't move anymore otherwise we do the set timeout and everything else and we call a callback now let's go back to this idea of having a success and a failure callback so i could pass in here's what i want you to do if we can keep moving here's what i want you to do if we can't move anymore for example i could reset the position if we've gone all the way to the right or i could just alert something the way that we would structure this and this is how a lot of older javascript libraries are actually written they have two callbacks you pass in so your request or whatever you're doing oh my gosh autocomplete here here we go and you pass in your success callback which you wouldn't write like this and then a fail callback so those are two functions as arguments so you would have your first function do something and then your second function do something else so let's try it let's rewrite this so we have our first callback let's call this on success and on failure or on fail so down here if we've made it to this point that means we can keep moving so we'll call if on success which uh i guess we can just assume our code let's just assume that it will be passed in just to make our code simpler we'll do on success right there and on failure will be right in here so now we have two branching paths you try and move a certain number of pixels if that number is too too big of a gap to jump and you'll be off screen this element will be off the screen we'll call the on failure callback otherwise we'll actually do that movement after some delay that you pass in and then call your on success callback so now we have to rewrite this whole thing to have two callbacks every time so i'm going to leave the original and i'll call move x of our button let's move 100 pixels the first time after one second one thousand milliseconds this is our success callback if we're successful we'll do something so i'll just write success then we have to add our second callback here so a whole nother function and this is if you cannot move if this is too big of a jump to try and make what do we want to do why don't we start with a simple alert cannot move further okay and so then if we're successful we'll do another move x this time why don't we move 400 pixels after one second here's our success callback we'll do something if success i'll label these success and then we have to add a fail callback to this function call and already it's getting quite messy so this would be our fail for the second callback or for the second attempt and here's our fail for the very first movex so fail here we'll do the exact same alert cannot move further and if i save it gets all formatted funky um but this is a lot to just follow and try and read with your human eyes it's really not pretty and this is only two levels so far just adding in that second callback really complicates things this is relatively easy to look at and understand this happens then after this callback will happen then this callback here when we have two callbacks at a time we pass in it's just clunky and ugly okay so movex button let's see here's our success let's do one more move x so if we move 100 pixels we're still good this calls or this is called we try and move 400 pixels if we're still good this function is called otherwise this fail is called so movex this time let's do button something very large like 700 pixels that should do it for us at least if i shrink my screen down and then after a second again here's our success callback we'll just console.log really we still have screen left or something like that and then we pass in our failure callback here and this one will just alert cannot move further oh boy i mean look at this this is nasty to look at but let's just see if it works so we every single time we call move x we're now passing in two callbacks the one to call if things work and we can move the one to call if we can't move that far we'll be moving off screen and then as soon as we start nesting them it just grows into this absolute spaghetti mess so let's try it i'm gonna refresh my page okay so it actually did work but when i'm when i hit enter and close this alert you'll see what it's kind of behaving oddly or it might seem like it's behaving oddly this is because of our set timeout and what's happening if we go back we're moving 100 pixels then 400 then 700 if we can but because this code is running right away we're not doing it in the set timeout it seems like we're stopping too soon but as you saw here okay it stops or it appears to stop but i hit enter it still moves so that alert is actually coming from this move when we moved over here we could fix this problem if we move our conditional into the set timeout just to run through what's happening here we're moving 100 pixels but when we move 100 pixels we're starting by checking can we continue to move all right we can so we don't run this and we set a timeout this time out takes one second if we pass in a thousand milliseconds it takes 1 000 milliseconds for it to run and then call on success but as soon as that on success is called this code runs immediately this is not part of the thousand millisecond delay for the next time around it's happening at the very beginning of the function so we could rewrite this by moving this code into our set timeout this isn't necessarily the best way of designing this it might be better just to short circuit and just check as soon as possible if we can't move further but this will make it easier to see when it's working for us so now we're doing basically running the code at the exact same time we're checking if we can go and we're calling failure if we can't go we're calling success if we can move and we're doing it all within the set timeout so now it moves it moves again and then it says okay i can't keep going so we had the same outcome last time it just was alerting us before we had actually moved okay so this is looking great it works right it's stopping when it should if i expand my screen all the way over here let's see it now should be able to make that jump and now we get really we still have screen left which is our success for our third move so you can see this is quite ugly and this is only three moves what we had here was what five moves so why don't i take a second to recreate this i won't make you watch i'll just do it really quickly and through the magic of editing it will be done there you go so i decided to change it to 300 pixel jumps because i know some of you will have wider screens or you won't have your console open like i have here so i wanted to make sure in most cases that this would hit the edge of the screen so i'm going 300 300 300 300 300 and then each time if it fails i have this failure callback it's just alerting cannot move further cannot move further cannot move forever oh my gosh can't talk five times i have to rewrite that code i don't have an easy way of getting around this i have to pass in that failure callback even if i'm just doing basically the same thing every single time and then on our last success instead of continuing to move i'm just alerting you have a wide screen so let's see what happens now we move one time two times three times four and then it stops cannot move further and if i close my console i think we'll be able to make it to the end three four five and then the callback which is you have a wide screen oh ok so this has been a ton i know this is an incredibly long dense video i wanted to illustrate a situation where callbacks are useful we have to use callbacks with what we know so far in order to write a function like movex where we're waiting for something to finish and then running some code we're using settimeout all over the place in our source as you see where you set timeout and in order to to make our functions work the way we've written them we have to pass callbacks so we have a on success and on failure remember all of this stems from the fact that javascript does one thing at a time and the browser is taking over when we call set timeout the browser is keeping track of time and then it tells javascript okay time's up run this function and within this function we have some logic and then we tell javascript which one of these to run based off of some conditional logic so this all stems from javascript's fundamental nature the fact that it's single threaded and we have these browser apis the web apis that javascript works with to make a request to set a timeout to set an interval to add an event listener the browser takes care of that and then tells javascript all right here's a function here's a callback that's great but it can get really messy when we start having different outcomes a success in a failure which happens a lot when we make requests this is a very simple example but as you'll see shortly when we make requests real web http requests we follow the same pattern we have some code to run when it when the request works we have other code to run if the request fails and so if we structure our code like this on success on failure we have two callbacks things get nested ugly and very difficult to follow quickly i mean look at how separated our code is yes part of it is the way that my vs code is formatting things but even if we don't have all this indentation it's still really difficult to know you know if you want to change the failure callback for this first move x you have to scroll down and just make sure you're at the right level right you have to here's the first one here's the second failure third failure it becomes hard to to really follow and understand so this is where promises come in promises allow us to rewrite a function like this or this function here so that we don't have to do all this crazy nesting it's so much so much easier to read and that's what we're going to see in the next video so all of this has been set up for promises but uh as long as it's been this this video i know is probably the longest video in the course a real slog i congratulate you if you made it here and it will really help you understand why promises are worth it otherwise if i just show you promises without showing you the struggle without promises it doesn't do promises justice so that's coming up next alrighty so in the last video we saw how using a bunch of callbacks and nesting things can get really out of hand quickly this code is just long and difficult to understand when we're passing in two callbacks to each function call here and they're all nested there's a term for this sort of a playfully loving term in javascript called callback hell and you can see another example of this here on the left lots of nesting lots of functions that are nested functions they're being passed as callbacks this is just not very fun to write and it's especially annoying when it gets really long and super far nested and indented and it's just hard to follow so this is where promises come in promises allow us to write a synchronous code that is much easier to read and understand it's usually shorter but even if it's not actually shorter in terms of the number of characters it's much flatter often it's not so nested so here is where we'll end up this code written or rewritten to use promises looks like this a whole lot flatter much easier to look at on your eyes much easier to fix or debug something if it goes wrong we don't have to figure out which callback we need to update we don't have to you know find the corresponding fail callback for this success thankfully i have this bracket matcher which helps me but it's really obnoxious so this is where we're going it will take a moment though because we need to talk about the basics of promises when we work with promises there's really two different things you need to understand the first is how you create a promise how you could create a function that returns a promise and then the second is how you consume or interact with promises which we do all the time even if we're not writing the promises ourself we might be making a request from a library or using a library like axios which is something we'll see in just a bit it returns and a lot of its functions return promises so we need to understand how we work with those promises so we'll tackle both of those creating promises from scratch and then also just working with promises that someone else made okay so let's talk about the basics a promise is just an object it's a javascript object which represents the completion or failure of some eventual process something that can take time usually it's something that takes time otherwise you probably wouldn't need a promise so a promise is a way of promising a value that you may not have at the moment think of a promise in the real world when i was a kid i really wanted a dog i asked my dad he said you know i promise we'll get you a dog if you get good grades i got good grades and well he didn't follow through on the promise until he had new kids and then he got them a dog but other people's parents would probably follow through on those promises and actually follow through and give them a duck if the kid's a dog so a promise is different than saying here is a dog right now it's just a a guarantee or a supposed guarantee of an eventual value or a dog or whatever we're talking about so in javascript promises are objects that represent an eventual either failure or success of some task that takes time you make a request if we use a library like axios which we will shortly that returns a promise because that value if you're making an http request i could take time and that value may never come back it might be a failure or it might be successful and you might get some data back from an api but it takes time so the object that is returned in the meantime is a promise and what we do is we attach callbacks to that object so we don't pass in two callbacks or a single callback to a function and nest a whole bunch of things promises are objects that we can attach callbacks to instead this may not make sense at the moment but why don't i start by showing you how it works and it should click after a bit of practice so the way we make a new promise in javascript is like this new promise with a capital p i'll save this to a variable let's go with this idea of my parents promising me a dog const will get you a dog equals new promise and when we create a promise we pass in a function and this function has two parameters always these two parameters we usually call resolve and reject and these are actually functions and at any point inside of this function here this function that we pass into new promise if we call resolve the promise will be resolved if we call reject which is a function like this the promise will be rejected now what does that mean for a promise to be resolved or rejected well why don't we just start with doing neither we just have our promise here new promise that's it and we're not doing anything in it let's see what happens if i take a look at we'll get you a dog i'll refresh my page we'll get you a dog is a promise object and see that it has this one property called promise status which is set to pending so the promise is it is a promise but it has not been resolved or rejected it has not been fulfilled or it has not been broken if we were talking about this idea in the real world of a promise when someone promises you something we would say the status of that promise is pending until either they break the promise or they follow through on it so if we don't reject or resolve a promise its value or its status will be pending so the pending state of a promise is frequently what you will see initially when a promise is first returned if we're making a request and that takes 10 seconds which would be horrendously slow during those 10 seconds we don't have a response we don't know if it's a failure or success if the response went to the right url if the server was up if your internet was working so it would be pending but if i immediately call reject which is a function if i just write reject here it's not going to work i need to execute this function reject refresh the page take a look uncaught in promise we have an error that we didn't catch and our promise status is rejected and if i instead resolve like that refresh take a look at will get you a dog promise now has status of resolved so still not very useful at this point but this is the most fundamental part of creating a promise we call new promise we pass in a function and this function has two parameters resolve and reject you can name them other things but this is standard and when you call that first function which should be called resolve it resolves a promise it fulfills it and the status is set to resolved and if we instead reject it the status of that promise is rejected okay so now why don't we make something slightly more interesting we have we'll get you a dog why don't we write a promise that is randomly resolved or rejected so that's pretty much the logic my dad used to decide if i was actually gonna get a dog i'm pretty sure he just picked a random number and decided nope there was no real rationale here so why don't we uh pick a random number we'll do const rand equals math.random and then if rand is less than 0.5 we will let's do resolve else we will reject so now this promise every time i refresh the page should be one of these states either immediately resolved or immediately rejected depending on that random number so this time it was resolved i tried again resolved okay now it was rejected so this is the first part this is how we create a promise the next and also extremely important part is how we actually interact with the promise how do i run code if this promise was rejected versus run code if this promise was resolved this is where we meet our friend dot then so every promise has a then method so we could call will get you a dog dot then and this dot then method will run if our promise is resolved so i have my dot then and i'll pass in a callback this code will run when this promise is resolved and we'll console.log yay we got a dog so let's see if it works okay so it was rejected this code did not run refresh again this time if we take a look it was resolved and our callback inside of dot then was executed try it again rejected we don't see this code there's no yay we got a dog so we have another method we can use with every single promise we have dot then and another one called dot catch well it's not called dot catch it's called catch and we could just chain it on like this we could also do will get you a dog dot catch this code will run if the promise is rejected well console.log how about a sad face no dog so if the promise is randomly rejected this will print out if it is randomly resolved this prints out no dog it was rejected as you can see status is rejected once again rejected rejected there we go resolved all right so what we've seen so far may not seem that useful or revolutionary but we've seen the two basic pieces of working with and creating promises to make a promise we call new promise every single time we pass in a function and that function has two parameters resolve and reject within this function we can then call resolve as a function to resolve the promise we call reject as a function with parentheses to reject the promise and if we do neither the promise will have a status of pending until it's either resolved or rejected so that's creating a promise then we saw the dot then or the then method and the catch method whatever we pass into then will automatically run when a given promise is resolved and whatever we pass into dot catch the catch method will automatically run whenever a promise is rejected so these are two methods on a promise a promise is an object so this creates a new promise for us and then here we're using two existing methods on those promises or on this specific promise we'll get you a dog these are the basic building blocks of promises and we're going to continue to build on these remember we will be refactoring some code that nasty callback hell we saw was that the last video plus we'll see how to make requests this will all start to make sense if you're if you're questioning it or if you're lost it just doesn't seem that useful this is not that great i totally recognize that but we have to start somewhere so next we'll continue on our promises journey all right so our current promise will get you a dog promise is either resolved or rejected immediately there's nothing that takes time in this promise there's no real reason to use a promise we could just write a simple if else and just generate a random number on its own and print out code depending on if rand was less than five do this thing otherwise console.log no dog pretty simple with what we've seen so far but now let's introduce some some delay so it takes longer what we'll do is just use a set timeout to simulate the number of years it took my dad to finally reject his promise of getting me a dog so i will keep this here so we have a record of it but i'll duplicate it and then in here instead of just immediately resolving or rejecting let's do a set timeout and our set timeout will have a function and the delay will be five seconds and then in that function the callback i'll move my logic to pick a random number and then either resolve or reject so now this promise takes five seconds before it's resolved or rejected otherwise those first five seconds it's pending which we saw earlier so the dot then code or the dot catch code whatever one of these runs depending on if it was resolved or rejected it won't run for five seconds so let's try it out i refresh it takes five seconds to do come on there we go no dog if i refresh and i quickly take a look at will get you a dog it starts as pending for these five seconds it's pending now it's been rejected one more time it starts as pending hopefully this time it's resolved nope okay one more time come on come on resolve it get me a dog seriously three in a row how about now it's pending what the heck just resolve oh the joy if you oh my goodness how many of these are gonna be in a row just resolve please okay this is horrendous luck oh my pending oh finally i just hit the absolute jackpot of rejected promises how many was that like eight nine in a row oh what are the odds when i'm recording but we finally get it it starts as pending and then it's resolved all right so this is our first example of a promise that takes some time takes five seconds it's kind of simulating making a request and having to wait for that request to come back it's eventually resolved or rejected yes we're just hard coding a five second delay for no reason but imagine that something has to happen over those five seconds like we're animating something and we want to wait until the animation finishes which we'll return to that was the original impetus for promises in this section we were doing a whole bunch of nested callbacks and it was hideous when we were moving that button across the screen so another thing that we frequently do is return a promise from a function instead of just making it one promise like we have here we could instead just get rid of my variable define a function we'll call this const make dog promise equals some function and this function will return a promise this exact promise we already have so we just write return so now i can call this function instead of will get you a dog i can do make dog promise dot then and i can actually just chain this on like that i don't have to well if i call make dog promise again and did dot catch that would be two completely separate promises and they may not resolve or they may not both resolve or both reject they could have different values but if we instead chain it like this we get around that problem and it's also just shorter and cleaner you could save the variable or the result to a variable you know d equals make dog promise and then do d then and d catch but this is just better there we go so let's test it out we'll wait five seconds come on and there we go it was resolved so nothing major that we saw here except for the fact that one we can chain dot then and dot catch together without having to create a variable or without having to reference the promise again i can just put a dot catch after a dot then and only one or the other will run in this case my promise is either resolved or rejected if it's resolved this function runs here if it's rejected this function runs here and then the second thing we saw was that we can make a function which returns a promise which is an extremely common pattern rather than creating a promise from scratch and saving it to a variable often we work with functions where we would call once we get to axios axios.get some url reddit.com that will give us a promise and we put a dot then in a dot catch after that so this function itself is not a promise we're executing a function which returns a promise just like we did here this returns a new promise it's either resolved or rejected eventually but in the meantime it's still an object it has a status of pending and when it is either resolved or rejected one of these will run okay so we have a lot more to cover so onwards we go the next thing to know about promises is that when you reject or resolve a promise you can reject or resolve it with a value and you'll have access to that value in your callback that you pass into then or catch which is really really useful because most of the time we're not just waiting on some resolve or reject that happens arbitrarily like a random resolve or reject we want to know why was something rejected for example in the case of a http request why did this fail and if it didn't fail if it was resolved what is the data that we got back that's the point of making a request at least most of the time as you're trying to get some information so we are going to make a fake request function here we'll call it const fake request and we'll pass in a url so we'll call this like fakerequest reddit.com or something or actually let's just do relative urls so slash dogs or slash login and it's going to take some time so we know that it's going to return a promise because it takes some time so let's do return new promise and then we have our callback in here the i think it's called an executor function executor function on the docs at least it doesn't really matter but we have our resolve parameter and our reject and then we'll do a set timeout and how long should this timeout take let's say it takes three seconds to make a request which is a pretty long time to make a request and then our callback that goes here for set timeout and what do we want to do in here let's pick a random number and decide randomly if this request worked or not and we'll resolve it or reject so sort of the same thing we've done before math.random we'll save that to variable const rand and then we'll check if rand we don't want it to fail half the time so let's say if rand is less than 0.3 we will reject to start just like this and then else we will resolve so so far nothing new we've already seen how to do this if we call fake request we don't even need to pass in a url because we're not using it at the moment so fake request dot let's just do a dot then a simple one and a dot catch we will console.log request worked and then in our dot catch we'll do a console.log request failed so this is kind of a recap of what we already know it's the same idea a set timeout faking something in the last video we were doing a dog promise but it was the same thing except i think there's a 50 50 chance now we have a 30 70. so if we run this it should take three seconds and we'll see either request worked or requests failed and i won't keep going hopefully we get a request okay one more chance give it one more chance uh all right well you'll just have to trust me request will fail at some point so this video is about how we can reject and resolve with a value we can pass information in to the resolve or reject calls so let's start with reject if we reject why don't we pass in a status code so a typical http response includes a status code you've probably seen 200 for ok or definitely most likely at least scene 404 not found why don't we just pass that through so reject and then let's pass an object in where status is set to 404 so now instead of our catch if something is rejected our callback instead of catch will run so we can add a parameter in now could call it data or response and then we can look at res.status console.log res.status and if this ever fails let's do one second just to make it easier come on it worked okay there we go 404 request failed so we have access to this data that we passed through just a single variable or it's not even a variable a single value we could pass more things like reject with this object and then i don't know what else would make sense in this context but we could put whatever we want in here we could also pass in two and then we just have a second parameter we could call it num now as far as resolving with a value or multiple values it's the same process why don't we do something a bit more useful like when we call fake request we'll pass in a url how about slash users and then we'll use that url to decide what to respond with we're pretending to be an http request we're mocking it out we're adding the delay why don't we start with a variable we'll call this what should we call this maybe data or pages sure it will be an object where we map a url like slash users to some information and how about our users will be an array an array of objects where we have an id for each one let's just say id of one username is bilbo and we'll just have two users in here to keep it simple id of five username will be um how about esmeralda okay so whatever url is passed in we will use that url parameter to access information out of pages let's just add a second page in here this one will be slash about and it will just be a string of text this is the about page okay so if you pass in slash users what we'll do is take that url and resolve with pages of url let's just call this data const data and then we'll resolve it with an object maybe so that we can include a status code of 200 which means ok and then we'll also include data and i'll just use the shorthand instead of data colon data we'll just add data so if we check it out we pass in slash users let's start with something easier how about slash about dot then we'll go with response maybe res again and we'll console.log let's go with status code res.status and then duplicate that into res.data which is the second thing right we have status and data that we resolve with and we'll go with data here let's see what we get if it does resolve and it did status code 200 data this is the about page now instead of randomly resolving or rejecting let's get rid of the random number and instead we'll reject if the url is invalid if it's not contained within pages so we'll get rid of all this or almost all yeah i'll just get rid of all of it and what we'll do here is check within the set timeout so we're still going to wait a full second or three seconds or whatever we'll check if the url was in pages so if data right we're just plugging this url in if data we will resolve with this that we already have else will reject with the object that has status set to 404 which means not found which makes sense the url you passed in was not found in our fake our fake application it has two endpoints right now why don't we test this out now so if i do about we'll see if that one works it should still work i'll change it to users actually and then if we try another one this time fake request will do slash dogs which does not exist in our pages so if url is dogs this line should be undefined so this won't run and instead we'll reject let's double check cool so our first one worked we got status code 200 from the then callback right here res.data were these two users and then the second request did not work we got 404 requests failed alrighty so in this video we saw that we can resolve and reject with data we can pass through some argument there in this case it was an object in both resolving and rejecting scenarios and then instead of our then callback we can add a parameter give it whatever name we want and it will have that data it will be passed whatever the promise was resolved with and then same thing for catch except when the promise is rejected this function will run and this parameter will have whatever value we passed all right so we're almost done with the basics of promises we have one other really important topic to cover which is chaining multiple promises what if we wanted to make another request after the first one we have a really nice way of doing it so that's coming up next all right so the last really critical part of promises is understanding promise chaining so i've updated the fake request function to now have a much more robust set of pages it's still pretty minimal but we have a couple different endpoints we can make a fake request to slash users which would give us something like this where we have an id for each user and i could use that id to make a second request to get more information about a user and this is actually a really common pattern where a website or some api is set up with some endpoint that gives you a little bit of information about every user or every i don't know dog in the uh the dog shelter or every post on a on the reddit home page then it gives you an id that you can use to make a second follow-up request using information from the first so that you can get more detailed information like i have here so if we wanted to mock that we would make a request to slash users a fake request and get this information back then we could take this id id of one and make a request to slash users slash one but we want to do that after this one finishes after we know for sure what that id is just like we would in the real world so if you pretend for a moment that this is real it's not just a fake object of pages where we're just hard coding the data in those ids could change there could be users that are deleted so we would ask for all users and then make a request to user slash one with what we know right now here's how we would do it fake request and then the url let's start with slash users dot then we have our callback which gives us a response and then what we would do is take a look at response.data that is the name that we used right if we come down here data and we want the id right here this id of the first user so the array is what we get back that contains two items if we just console.log res.data let's just pretend that we are on a journey with a real api here's what we get back an array so if we want to take the first user that would be console.log res.data0 if we want that id we could save that to a variable let's just make sure we're printing it out correctly after one second okay so let's save this to a variable we'll call it const id so we have the piece of information we need to make our second request with what we've seen so far it's just gonna oh i'm not printing anything well i'm an idiot nothing will show up but with what we've seen so far we would have to just make another call to fake request we have to do that either way we can't get around that but we would nest it in here because we need this to happen after this one finishes so logically it would go in the dot then if we put it down here it's not going to happen afterwards we depend on this id which we only have access to in this callback the dot then callback where the response is passed through so i have to do it in here with what we've seen i would call fake request again and we'll use a template literal to do slash users slash and then dollar sign curly braces my id i got from the previous request and i could do a second dot then same exact thing res and then we can console.log the response let's see what we get so we should get a first oh actually we're not printing the very first time so we only see the second response that we get back and it has more information about the user with id of one and status of 200 this all looks good if i wanted to make another request with that if we look at the data we got back we have this top post id so i now can send a request to another url i've set up in my pages object called slash posts slash and then this id so i could then make another request fake request and it's res.data dot what was it top post id yes so this is a third request that is dependent upon the second request which itself is dependent upon the data we got back from the very first request we got all users that gave us an id we could use we used that to make a request using that id now we get this top post id which we can use to make another request to slash post slash sum id so we'll do slash posts slash and we'll save this to a variable const id again or how about post id and then interpolate that with dollar sign curly braces post id one more dot then we'll get our response hopefully and then we'll do our console.log response okay we'll try it come on all right where did we get back yes we're getting our post information ladies and gentlemen may i introduce you to my pet pig hamlet so this was some hypothetical post on our website by this user so what we have here doesn't honestly it doesn't look much better than what we saw in the whole callback hell section of this section where we talked about nesting a whole bunch of things also we don't have catches right now so if i want to do that it gets even messier if i want to catch i would do catch pass in my callback and we'll just call this uh error and then console.log oh no and then we'll also just print the error so right now we don't have a way of causing an error but if i mess up this request and i use a wrong or an invalid url like that it should catch it and it does we get oh no here's our error it's a status code 400 or 404 and an object but if this one is valid and i instead mess this request up this is a url that doesn't exist in our pages let's see what happens it didn't work i mean the the promise was rejected but we didn't catch it like we have here so this catch is only working for this fake request so i would need another dot catch for this dot then so we have a much much nicer way of rewriting all of this what we're doing here is essentially the same thing we saw with callbacks where we just nest them and nest them and nest them this fake request is dependent on the data from this one this third one is dependent on the second one so it makes sense to nest them but we have a whole different way of structuring them what we can do instead i'll just type this sort of in a shorthand up here if we do a dot then and in the callback of the dot then we return a promise we can call that then immediately after on the same level i don't have to nest i can chain it and i can continue to chain as long as each callback for then returns a promise i won't nest my dot then so i won't have to do any nesting instead i return a promise this dot then runs first it returns a promise this dot then will run if the second promise the returned promise was resolved and so on so let me show you what that would look like we have our fake request.then and then we have this whole callback here we get the id then we have our second fake request here what i'm going to do is remove all of this right here and return this function call this returns a promise just like this did our function the first line says return new promise so this returns a promise we're putting the dot then on that promise then inside this dot then we return another promise and what i can do is put my next dot then on the same level so here i am doing another dot then getting the post id from the response i can return this fake request which returns a promise and i can move my dot then outside so if you look at my code now i should have saved the original where we were nesting things it was then and then inside that dot then we essentially had another dot then and then another dot then and we didn't even bother with catches that was still a lot of nesting now what we're seeing if you take my word that this does work is that we can write things in a much more linear way so do this then do this then do this so this will only run if the first promise was resolved meaning this ran then that promise that was returned the second promise was resolved meaning that this code runs in the dot then callback and this promise is resolved which would trigger this callback so if any of those screw up at any point and this is a real magical part we only need one dot catch so this dot catch will run if any of these promises are rejected we have this promise we have this promise we have this promise we only need one dot catch it's like a catch-all it's really really nice so right now we do have an error here it won't work so let's just start with it actually working so users then users slash the id then post slash the post id let's see what happens i'm going to console.log the data we get back each time so console.log res i'll do that here and you'll see them happening one after another even though they're not nested oh i'm doing it twice here okay moment of truth we get our first one second one third one it's pretty cool right we don't have to nest these take time but we don't have to use a bunch of callbacks and continue to nest and get crazy with that multi-level craziness multi-level craziness yeah all we have to do is make sure we return promise inside of this callback and then we can just add another dot then we could have as many levels as we want remember like i already said this is only going to run this.then if this promise was resolved and this one is dependent on this promise being resolved this one is dependent on this one so it doesn't look like we have this crazy multi-level dependency thing going on but that's the magic of promises we can rewrite our code in a much easier to read manner right do this then do this then do this then do this if at any point something went wrong do this so why don't we have something go wrong at the beginning we'll use a url that doesn't exist oh no okay so the the catch ran that callback now let's have something go wrong here so we have our first promise that should be resolved there we go then we get oh no and this code never ran right when we had an error with the very first one none of the other thens ran it went straight to dot catch and it was done but now if i have an error in this third request we get the first two resolved resolved rejected dot catch runs so hopefully you can see already even though we're doing very fake stuff it's a mocked request it's hard-coded it's stupid i won't say stupid it's useless in the real world it's useful in an educational context even though all of that is true it's still a good illustration of the benefits of using promises we can have multiple asynchronous actions that we want to happen one after another so not simultaneously but one after another we chain dot then as long as we return a promise each time everything works and we only need one dot catch so what we're going to do next is revisit the early example that i used to illustrate callback hell where we were moving a button across the screen we'll rewrite it with promises something slightly more useful instead of just an arbitrary fake request you'll see how much time well you'll see how much code it saves us and how how many headaches it prevents it's so much easier to read so that's next now that we're relatively comfortable with promises let's try and refactor this little demo from earlier where we had a button that was moving and eventually running out of room potentially and stopping so if we can't go further if we can't go whatever 200 300 pixels whatever the jump was let's see i think it was 300 pixels yeah so if we can't go another 300 pixels it stops and we achieve this by using a bunch of set timeouts and then changing the transform property of the button but every time in that set timeout we would check do we have room to move if we don't have room to move we would call one callback that was passed in the on failure callback if we did have room to move we called the on success callback so we ended up passing two callbacks in every time we call move x and if we wanted the first one to complete the first move of 300 pixels before the second one started we have to use these callbacks with the way that we've set it up without promises it's a bunch of nesting a bunch i mean a whole bunch as we saw very very painful so let's rewrite this using promises i'll comment this out so we don't get the original movement going on and i'll also duplicate this and comment it out and then i guess i'll do it at the top here we're going to refactor move x it's going to no longer accept an unsuccessful success and on failure it's going to instead return a new promise remember this promise takes a function as its argument resolve and reject which are also two functions and then we can move this logic from before into our promis con what is it called executor function maybe i'm making that up i'm pretty sure that's what it's called but inside of this new promise function so instead of calling on failure we would reject the promise if we can't move we're calculating the end of the body how much how many pixels we have let's say 900 pixels or something actually we can see it's telling me i'm at what 12 25 pixels then we're calculating the right of the button and then the current left of the button which we use if we are going to move and we want to check if the right whatever let's say 800 pixels plus the amount we're trying to move 300 pixels if that is greater than the boundary we'll reject meaning stop we're not going to continue otherwise instead of on success we'll call resolve so very similar code except we've wrapped it in a promise that we're returning and we're not using we're not passing in two callbacks every single time so now how would we use this it would look like this move x of button let's do 300 pixels and the delay of one second dot then and we're not passing any value in when we are rejecting or resolving we could possibly maybe when we reject we could include a reason we could include the um maybe the the current position of the element we could do something with it and then we've got our dot then uh why don't we just console.log done moving and start there so i'm going to refresh the page it moves and we get done moving okay so if we wanted another move x after that first one like we had before we moved 300 pixels we moved 300 pixels again one second later we don't have to nest it all we need to do is call move x again move x button 300 pixels over one second not two seconds and if i wanted another dot then yes you could do this put it inside the existing.then callback or we just return this promise this gives us a promise now which is what we saw in the last video we can chain promises and i can put another dot then here and now i can console.log done done with both okay so we do the first thing that takes some time when it finishes when that one second is over the button has moved assuming it has room which it showed we're only going 300 pixels then we're going to move x again which will return a promise it may or may not be completed or resolved depending on if we have the number the correct number of pixels the correct space to keep moving and if we do this dot then we'll run we don't have a catch yet but this should be good because we're only moving 600 total and then we get done with both so that only prints out after two move x functions are done both promises have been resolved so now if we wanted to do like five of them all we need to do is duplicate this a couple times so now we're moving four times first 300 pixels it takes a second as soon as it's done but not sooner as soon as it's done then this runs and then as soon as that finishes and hopefully it's resolved this runs then this runs we don't have a catch yet so we may run out of space 300 300 are we out of space now yes uncaught so we had a rejected promise but we didn't catch it and as we saw all we need is one dot catch and we'll console.log now let's do yeah console.log out of space cannot move and we should see one more time here we go outer space cannot move and if i instead changed it so we're trying to move like i don't know 3000 pixels on the third move x will still have the same catch work it will catch that promise which is rejected it will catch the error so let's try that first jump second jump third jump can't happen outer space cannot move now what's really cool is in situations like this where all we're doing in the dot then callback is returning another promise we can shorten it up as we've seen with arrow functions if you do choose to use arrow functions if you are returning something and it's the only expression the only line you can use an implicit return so you could use parentheses we don't have to write the return keyword we can just do this right here just like that and we can chain them together so i'm just going to replace what i have with a couple of these let's do five of them and keep our one dot catch so this only works to make it super concise and and just nice not a bunch of curly braces that only works if there's only one expression and it should be returned implicitly so we don't write return but it's being returned if you need some review on that check out the arrow functions section okay so let's check it out first move second move third fourth and then we run out of space awesome so i could change this to be 100 pixels and do this a whole bunch we'll see when we run out of space one more time is that still oh i guess we're moving 300 the very first time i didn't change that one and now we're out of space pretty cool stuff i think uh it's a really nice nice way of shortening your code up and making it it's not even about shortening it it's making it just easier to follow if we compare this is a huge mess not only is it nested but we had to pass in two callbacks so we get this ugly like i don't know what to call this like a triangle a pyramid mirror image the reflection there we go of all of these callbacks even if they're doing the same thing the failure callback here we just need a single dot catch and it does the trick so the last thing we could do is refactor this a bit so our dot catch could actually know this callback could know where it was stopped why we didn't keep moving to the right basically we know we're out of room but we could you know print out you the button is currently at 500 pixels and you try to move 300 but the body is x or who knows we we could just make a little object when we reject that included let's say the body boundary and i'll just use the shorthand here so body boundary will be the key and whatever it holds will be the value let's also add in the element right and the amount so we'll have three different properties that we are passing through when we reject then down here when we catch we can just add in our object we'll just call this you can call it error but it's not really an error we'll call it data as a parameter and let's grab we could just destructure actually if we want body boundary we want amount and what else was there uh l write okay so we can console.log something like body is let's do template literal string template literal body is body boundary px wide and then below that console.log let's say element is at l write px comma and then we'll display the amount px is too large okay so we reject with that information rather than just blindly or always printing out outer space cannot move let's see what happens when we finally hit that catch oh i forgot i did all these 100 pixel little tiny jumps okay here we go body is 1354 pixels element is at 1297 100 pixels is too large because that would take us to 13.97 and that's pretty much it so still a very simple example not the most useful thing to do ever but you can see what a massive difference is made i mean we're doing what 10 15 different calls to move x and they're happening one after another and all of them are handled if something goes wrong if they fail we don't have room this catches all of them compare that to this this is only five or so different move x calls if we wanted to replicate this i mean i would i would be here forever we would have at least twice as much code as we have right now and it would be incredibly nested and hard to keep track of so that is a real value of promises it's not just about doing asynchronous things and being able to run some code afterwards it's also about being able to catch any time a promise is rejected having a single catch it makes a huge difference we don't have to have 10 or 20 different catches one per each dot then for each promise as long as we return a promise in the dot then which is what we're doing thanks to an implicit arrow function return all right so we're now moving on from our sort of playland promises where we're doing very very trivial simple things and next we'll move on to making real http requests and use promises those functions those methods return promises so we'll get practice with all this fun stuff that we've seen so far
Info
Channel: Code With Sahib
Views: 345
Rating: undefined out of 5
Keywords: Asynchronous Code, cocoaheads, ios, kyiv, cocoaheadsukraine, Synchronous reset, asynchronous Reset, asynchronous Reset in verilog, synchronous Reset in verilog, difference between synchronous and asynchronous reset in verilog, synchronous and asynchronous Reset, Different type of reset in verilog, Verilog code for synchronous and asynchronous Reset, example of synchronous and asynchronous Reset
Id: JpSKAAmVaw8
Channel Id: undefined
Length: 113min 35sec (6815 seconds)
Published: Wed Nov 25 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.