How to Use Javascript Promises

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right how to use JavaScript promises so javascript promises represent an alternative system for managing asynchronous requests in your codebase and when I say alternative I mean an alternative to callbacks if you've written any JavaScript code in the past you've definitely used a callback function before something like this jQuery Ajax function you know a user clicks on a button you make an asynchronous call to the server to fetch data and then you have a callback function as a success handler that runs once the data comes back and you do some sort of logic on that data most likely updating a UI and callbacks work great when your logic is as simple as like make one request get one result do one thing but in the real world async is much more convoluted than that you'll be making multiple requests simultaneously and the UI logic might be different depending on which one of those request returns first or you might want to have the logic on how to call the API server in a different part of your codebase from the logic of what to do with the data once it returns and promises just make it easier to manage multiple asynchrony cleaner when you have real-world applications the only trade-off is that it might just be a little bit more confusing at first to wrap your head around the concept of promises but once you get it it makes perfect sense and you'll be using promises in your JavaScript code for the rest of your life ok so just to clarify promises are a design pattern this is not to be confused with a promise library promise libraries are specific implementations of the promise design pattern so things like queue or things like Bluebird these are promised libraries these are actual implementations of just a design pattern but there's also now a native implementation of promises in JavaScript itself so you can use the promise design pattern without needing to include any external libraries or frameworks whatsoever ok at a high level there's only two concepts that you really need to wrap your head around for this to all make sense to you the deferred object and the promise object you can think of the promise object a little bit like a progress bar it's kind of hard to understand because it's a physical representation of an anja BoConcept it's just this idea of something that's currently in progress and it's personified as a JavaScript object you know the task might not have finished yet and you might not have access to the data to run an operation on but you want a reference to that in progress task itself so that you can write logic around it you know an example of this would be like I want to run three separate tasks and then aggregate the results when all three come back and then do something with that data even though the tasks might finish at different times and and that's kind of a hard concept to represent in the callback model because you don't have access to that in progress object but you know if you did you could write that logic a little bit easier where it's like I want these three in progress objects and when they all finish I want to do something with it so if the progress if the promise object is a progress bar the deferred object is like an interface into that progress bar so you don't actually like make updates to that progress bar directly you update it through this deferred object which serves as its interface and I know that's like kind of a really crude example right now but I guarantee that this will make sense as we keep going so as we get into the the rest of the screencast I just want to say like just my advice would be to just power through watching it once and then go back to the beginning and watch it again because this stuff will mix and more and more sense as you go so just if something isn't making sense just keep watching and I think it will start to dawn on you and then if you go back and watch it again it all makes sense okay we start with a deferred object the deferred object is just a JavaScript object but it has a property on it called promise which is the promise object now these are two separate objects you can pass the deferred and the promise in two separate functions and operate on them independently but you can always get to the promise from the deferred object because it's just a property on it you can call deferred dot promise and get to the promise at anytime now the promise has two properties on it itself it has a status and a value by default when you create a promise the status is pending and the value is undefined now let's stop right there for a second and see what this looks like an actual JavaScript code okay so I'm not using any libraries or frameworks or anything like that this is just the JavaScript console in the Chrome browser if I want to create a new deferred object I can just save our deferred equals promise dot defer and that creates a new deferred object if I look at it in the console I can see that it has an attribute on it called promise if I want to isolate the promise I can set a separate variable equal to deferred dot promise and if I look at that I can see that it has a status of pending and a value of undefined now just to again confirm that promise object is the exact same promise object as the property on the deferred object so in addition to having a property of promise the deferred object also has two functions that you can call resolve and reject and in addition to having two properties the promise object has two functions that you can call then and catch now the good news is that this is the end of the chart if you can understand what these functions do you will understand promises no problem so what does the resolve function do well if you think of the promise as a progress bar the resolve function is saying this is no longer in progress it has completed we have finished and gotten a value from our calculation so it's going to tell everyone that was referencing that progress bar hey it's not in progress anymore we have the value you can go ahead with the rest of your execution of your function so when we resolve a promise we resolve it with a value and that becomes the value of the promise and then any function waiting for that value now uses that value to continue its execution so we resolve a promise of the value it can be any JavaScript value let's use an example a number for simplicity I just randomly chose the number 17 so in this hypothetical example we resolve a promise of the number 17 and look at what happens it severs its connection to the reject function so if I called reject on a deferred object after it's been resolved nothing will happen now after a resolve a promise the promise updates its status to resolved and it will update its value 2:17 the value I resolved it with this will also trigger the then function to anyone that had been referencing the promise and it will trigger that function with the argument of the promises value passed in it will also sever its connection to the cash function so let's stop there for a second and take a look at what this looks like in code okay so I have my deferred object from before and if we expand it out we can see not only does it have that property of promise it also has two functions reject and resolved and I still have my promise object from before which status is pending and value is undefined so let's attach a listener to it let's do promise that then takes one argument which is the value the promise will be resolved with and let's just console dot log value times 10 and if I hit enter notice that nothing happens because this function hasn't been triggered yet this function is only going to be triggered once the promise is resolved and you resolve a promise from the deferred object so let's do deferred dot resolve with the value of 17 and notice that our function was triggered a console dot log that value times 10 to 1 seven-day and if we look at the promise we can see that it's status has now been resolved and its value is 17 so we resolved a promise or the value and went down the green branches but if for some reason we get an error in our asynchronous request we can go down the red branch's instead and we can reject the promise now when you reject a promise you you can pass in any value you want but normally you pass in a JavaScript error object so let's say something went wrong with our server was down or something we choose to reject this promise with a 404 error now look what happens the resolved branch is severed so if you reject a promise you can no longer ever resolve that promise it's gone for it's rejected for good the the status of the promise updates rejected the value becomes that error object and we go down the catch branch and we pass the air audit in so anything downstream that was listening on the dot then function knows hey this promised error doubt don't execute that then function you can catch this error and handle it so let's look at that in code okay so let's make another third object promise dot fur and let's make another promise object deferred promise now let's attach a then function to this promise that does exactly what we did before we'll just console dot log value times 10 but we'll also attach a catch function catch error and we'll just console dot log promise a caught in error and will log the error message also so we've attached it then listener a catch listener so far nothing's happen because the promise is still pending but instead of resolving it with 17 let's reject it this time with a new error and we'll just add the message something went wrong now if I hit enter notice that promise caught an error something went wrong so the catch function fired but this dot then console logging value times 10 this is never fired so as fun as it is to look at my awesome keynotes it's probably a little bit more valuable to see what this actually looks like in code so this is just going to be pseudocode right here but you might do something like this in an actual code base so on my left hand side we have some sort of UI domain logic and on my right hand side we have some sort of api service so we might make a class here that's called api service and it might have some function called get data that takes an endpoint as an argument and watch what we do here we're going to make a deferred object promise that's a fire and then we're going to return the deferred dot promise from this function and we will come back to this and we might do module dot exports equals new API service that we can use this in other files now in our domain logic we might get a reference to that API service and we might make a function called load data that takes an endpoint and we might do something like this where we call the API service dot get data endpoint and remember this function now returns a promise so we can just call dot then on it with the data that gets returned and we can do something with this data and if it returns an error we can catch the error we can handle it and then we'd call like load data and we pass it some import so let's go back to here the way that this would normally work is you'd do something like call fetch which is the JavaScript function that makes HTTP requests you give at the endpoint and some sort of fetch config which we haven't defined but whatever and fetch actually itself returns a promise so you would do dot Van is data and you'd use the result of that promise to then resolve the promise that you had created beforehand so let's look at this code right here we're making a deferred object in the API service we return the promise and then make some async call and we wait for it to resolve and then in our UI logic all that we're saying is go get data from the endpoint and when you have the data back go do something with it then this resolves this then function gets triggered but we have really good isolation here because our domain logic on our left-hand side it does it's not concerned with how the API is implemented it just says call out to the API get the data back and then do some sort of domain UI thing and on the right-hand side we have really good isolation because the API service isn't concerned about what's happening with the data it's just concerned about how we can you know go to the API get the data and it just returns a promise and anyone that wants to hook into it can so I mentioned beforehand that promises give you a lot more leverage over managing multiple asynchronous API calls and I want to give you some examples of how that might work to give you a little bit more color on why promises are so valuable so let's look at this scenario where we have an Instagram post this is a self-driving car flipped over in the Tenderloin district of San Francisco I'm just kidding I don't know if it's actually a self-driving car but it definitely sums up my experiences in the Tenderloin but anyway in order to generate this image we might be getting the picture itself from one API source we might be getting the username and the user profile picture from another and we might be getting the light count and the user names that like the picture from a separate API source but we don't want to render this actual post until we have data from all three sources because we don't want to render a partial view so we have kind of this scenario where we want to reach out to multiple different api's and we want to aggregate the data together and wait for it all to be back before we update the user interface so I'm going to create three separate deferred objects and then I'm going to go ahead and create three separate promise objects as well now I'm going to use the promise dot all function which takes an array of multiple promises and then only fires the then function if and only if all promises in the array have been resolved so I'll give it P 1 P 2 P 3 and I'll give it a vent and it'll take the values so it takes an array of what the values will be when they've all been resolved and let's just sum this array as an example so reduce memo I return them o plus I and let's go ahead and resolve the first result resolve the first deferred object I'll give it the number 10 and notice that nothing happens I'll resolve the second deferred object the number 15 again nothing happens but now I'm going to resolve the third deferred object which means all three promises should be resolved I resolved with the number 25 so this should sum to 50 and sure enough when I hit enter we get 50 so all three of deferred objects have been resolved all the promises have been resolved fires off the function sums the array gives us 50 and now remember since our API service returns a promise if we want to implement this in code we can do something like this promise that all make this endpoint one put that there we could do API service get data and point 2 comma API service get in point three and then just put the dot down on the values here values do something with the multiplies and if any of those valid and if any of these async calls are out we'll go down to our cash function so yeah really nice code so here's another scenario say we have this user interface with pagination where we have page one selected the content from page one on the main UI but this pagination at the bottom where we can go to the next page and this all happens asynchronously so I click on page 2 it is synchronously it goes and gets data from the server data comes back and it uploads it updates the UI with page 2's content that's all good and well but what happens in this scenario we have page 1 selected and pagination page once content in the UI I click on page 2 it goes and fires off its request but before it's comes back I click on page 3 and then before that comes back I click on page 4 so now we have three outstanding asynchronous requests and and you know it's anyone's guess what's going to happen maybe page 2 comes back and it updates the UI page 2 its content but then maybe page 4 comes back it updates the UI page 4 is content and then page 3 comes back and it updates the UI page 3s content so not only have we had our UI flickr 3 times which isn't good in the first place but now we're stuck with page 3s content on the page with page 4 selected in the pagination so this is really bad there's nothing we can do about in this situation but if we really go back to what we should have done right here when we clicked onto page 4 we know that you can programmatically reject a promises defer dot reject so really we can set up a situation where when we have a new API called it takes precedence over an outstanding API call that hasn't returned we can just reject that promise so that when it comes back the then function never fires and it never updates the page another great example for this would be any kind of like search as you type kind of functionality where as you're typing keystrokes it's executing a live search but if you type in a new keystroke you don't want a race condition where you might get old search results with new string so you just want to cancel any outstanding promises quick pseudocode on how that might work we click on page 1 we make a new deferred object we attach a listener to it that will just console dot log the data and then we click on page two before page ones data has returned so we make an a deferred object for that but we also when we create this will reject any deferred objects that are outstanding so we go ahead and reject D one the first deferred object which is manually rejected now save the data for page two comes back and this is a good UI update because this is what the expected behavior so that that gets resolved now the data from page one comes back and this is a bad UI update that we don't want to make but nothing happens nothing is console.log because the d1 promise has been rejected it's been manually rejected so even though when that came back out of sync our UI isn't affected another thing you might want to do is chain asynchronous API calls together so for example we have an API service we make one API call to it to get an API token and then we need to use that token to hit the service again to make an API request and get our data back so this is like kind of one API called one after another you can chain promises together just by returning a value from the dot den function so say we go to endpoint one and we get a token back and in this scenario we need to parse it because it's in Jason and we need it as a string so we could return Jason dot parse token and then just chain another dot then which now has a parse token which we'll use to make the second API call so we can return API service get data and point two and then because we're returning the promise we can then chain it together and this will be our data and now we can do something with data and if any of these fail then we can just catch and handle the error and look how nicely that kind of composes together versus how messy that would be if you had to kind of nest callbacks in each other yeah so hope that makes promises make a little bit more sense use them everywhere in your codebase they're seriously amazing and yeah feel free to get in touch if you've got some feedback on how this kind of or Matt works for coding screencasts or if you've got any ideas for topics I should cover in the future peace
Info
Channel: Decypher Media
Views: 106,498
Rating: undefined out of 5
Keywords: javascript, promises, javascript promises, introduction to promises, javascript promise exmplanation, javascript promise tutorial, always be coding
Id: 104J7_HyaG4
Channel Id: undefined
Length: 19min 44sec (1184 seconds)
Published: Sat Apr 02 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.