forEach is BAD! for Async Await Code | Advanced Async/Await Javascript Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome hi i'm dave today we're going to talk about why using four each is not a good choice in most situations and some have gone so far as to say there is no place before each and modern javascript i'm going to show you why along with several good alternatives so let's get started okay i've got visual studio code here on the left and on the right i have got chrome dev tools with the console available right here so when we first learn about using for each we think it's great because we don't have to write out all the syntax of the traditional for loop so we could put a for each loop into action actually let me put it into a function that we can call so i'll call this use for each we'll pass in the ids array that i have up above that just contains the numbers 1 through 10 and then inside this function we'll take the ids and we'll call four each and then we'll have four each id and then let's just log to the console each of the ids and then after that of course we need to call this function into action so we'll put it up here in the init app function and we'll say use for each and we'll pass in the ids and what i've got here is an array of ids and then i've got a document add event listener that listens for the dom content loaded event and when the dom content is loaded we call the init app function which is right here that would kick off the whole web app if we were building a web app but i'm just calling this use for each function we just created inside of the init app function so once the dom content is loaded that will be called into action we can save this and you see in the console over here we log the numbers one through ten everything works as expected and the fact is is when we're learning javascript we use console log a lot and it's a side effect what that means is it's not something returned by the function it affects something outside of the function it's definitely not for use in a pure function which i have a separate tutorial on but before i get off track the point being is for each allows us to loop through something but it doesn't return anything and that immediately makes it less useful than the other higher order functions say like map that do return something like a new array but what i really want to focus on today is why using async and await with for each is no good so let's take a look at why i'm going to start by pasting in another async function and this is going to make an api request using fetch to json placeholder and we're going to fetch some ids it looks like i need to wrap the code so you can see the end of the url but you see we're passing in an id here each time and also notice that i am awaiting the json method i'm doing this all in one line here so oftentimes you'll see result equals weight fetch and you get the results from fetch and then you take those results and you call the json method well i just put it all in one line by putting the await fetch in parentheses and then another await on the outside here and the dot json at the end and i'm returning that so if you haven't seen that before it's not really anything new i just made it one line where you usually see two or three lines awaiting say const result equals fetch and then awaiting uh the result.json and you might return that line or you might have even set that equal to data and then return data on a third line it's all in one line anyway that's our get post function it's async and we're going to use it inside of four each to show why for each is a bad idea with async await first of all let's take this console log and put it on a separate line and then we need to add the curly braces for that to get our for each correct there we go down here at the bottom and now if we're going to use git post inside of here and we'll use it with the ids because we can pass each individual id into this url with git post what we need to do is once again say for each id and we're looping through the ids but we would want to call async right here because for each does call a function so if you're trying to use async with for each that's where it would go then instead of logging here we would want to await and then have git post and pass in the id and then let's let's go ahead and set this equal to data so let's say const data this is just the raw data that we get back from json placeholder and then let's go ahead and just log this data that we get back now there will be an issue here and we'll look at the console to see what the issue is so once again we're still calling use for each up here we're still passing in the array of ids but now we're using that array of ids and calling each id inside of the for each loop and we're calling get post inside of that now let's see if we get the results we expect i'll go ahead and save and we should see a change over here let me maybe shrink this text inside of the console so we can see it just a little bit better and that's a little blinding there from visual studio code so let me pull this back up there we go so we've got the dark theme going everywhere which is easier on my eyes i hope it's easier on your eyes too so if we scroll up here to the top user id but look the first id that we've got in the console is 9 and then 10 and then two and then seven and three and i think you see a problem here really four each isn't waiting on any promise to fulfill at all it's just rocketing through that information and so we're not getting this back in the order we requested it so it's definitely not a synchronous order as far as our array is concerned it's just kind of throwing away those promises and going ahead and calling the data and what's worse than that see it doesn't return anything so we can't really put async up here let me try to do this here i've got caps lock on there we go async and then you would think okay we could put a weight here but it doesn't return anything so we're not awaiting anything so i can put a console log down here and say i'm not waiting and there we go oh that's a problem quotation marks and get the correct quotation mark here since i'm using a single quote inside so i'm not waiting in the console log go ahead and save this and notice i'm not waiting is not at the bottom it's up here at the very top because we didn't await for anything to resolve here so this async here and the weight here is really doing us no good and we can't let our for each loop resolve these promises that we would get from git post and then do something here and we don't know what order we would receive them back in either so let's look at some good alternatives to replace this where we don't want to use for each with async await okay i'm just going to paste this function over the use for each function and it's called get posts serialized we can look at this it's an async function and we're using a traditional for loop because why use a sledgehammer when we just have the accurate tool that we need even though you may not like writing out all the details of a traditional for loop where we define uh say the iterator here let i and then you've got i less than the length of the array that's passed in and then we increment i that's your standard for loop but look we can await git post and we can log the data and there's no separate function this isn't a higher order function so it's just part of the greater function overall and therefore we can async on the the get post serialized the overall function and await git post and then notice i've got this all weighed on you down here just to show that we can get through this for loop wait on the data in the serialized order and that's why i said serialized it should keep it in the post order id 1 through 10 and everything should go as expected so i'm going to take this and replace our use for each in the init app function and i'll scroll back down where we can see this better and save and let's look in the console oh i've got a problem get post serialize has already been declared in my code and save now i had git post serialize declared just a little bit lower before as well so i fixed that now i've got all weight on you at the bottom so the console log statement didn't happen until we got through the for loop and notice number 10 is here at the bottom and as i scroll up it should be in the correct order and yes everything is so we start with id of 1 then id of 2 and count right on through number 10. so it may not be as cool as using a higher order function but a simple for loop will get the job done with async and await in the serial order that we need now although the for loop works in modern javascript we have a better solution and i'm going to paste this in just underneath so you can compare or if you want to pause the screen and look at both to see the difference but if we use a four of loop we can really eliminate some of that tedious syntax of the regular for loop and we can iterate through an array so here we have four id of ids and then we basically have the same thing here where we await git post and we're logging the data and now i'll just get rid of this for loop and we'll go ahead and save and we'll see we get the same thing in the console and we also still get it in the serialized order one through ten so all weight on you is here at the end and we get the same order we needed starting with one and ending with ten so this is how i would write this if i was just going for a simple solution but let's look at a couple of other solutions as well so far i've focused on solutions that would keep the posts serialized that is delivering them back in the order that we kind of feed the function 1 through 10 or the for loop just in itself however if that's not such a concern let me paste another solution down here and i called this get post concurrently shout out to james q quick that has a great uh video on i would say promise all i guess was what he was focused on but he was also talking about uh parallel versus concurrent and he chose to use the verbiage concurrently which i agree with uh you will see some people say get the request in parallel but that's not quite fitting the definition as good as concurrently so i agree with james there thank you james so let's look at this function we've got git post concurrently it's an async function but now we're getting something back we're getting something back from a promise all here as a matter of fact and we're using a higher order function map notice this line is wrapping so at the very end we're calling git post as well but map returns an array so what happens here is we get an array of promises to resolve this will resolve them all at once so notice we don't have the await in front of get post we have the await in front of promise all and then once we get all of those posts they're resolved here and notice i do have the all weight on you because unlike for each map is returning something and then it's all being resolved here at the very end so i'm going to go ahead and change this up in our init function i can leave the get post serialize definition here but up here i'll just replace it with git posts concurrently and let's save now we may get these in order or we may not but the key is and here we're seeing the uh bright background as well but the key is that uh it's faster and so what happens here is we're getting the full arrays the way i logged it and because that's because we get them back all at once as well but here is id of one and i guess i need to go down here to look at the next one id of two so apparently they are in order right now but it's not guaranteed to be that way we won't necessarily get them back in that same order so let's come back to visual studio code that is so bright when i look at it that way but what i wanted to point out is this is faster if the serial order isn't as important to you however now promise all and i could do a separate video on promise all if one of the promises fails they all fail so what you would want to do if you wanted to check the status allowing some to fail and some not to fail and still get something back you would use promise all settled and let's go ahead and do that as well i'll save this now and you'll see the object we get back is just a little bit different it has a status here and it says fulfilled and then it has the value that has what we were looking at before so promise all settled is just a little bit different than promise all okay i'm going to change back to the get post serialized and we're going to redefine that function once again it may look a little complex for some of you that are not as used to higher order functions so i would suggest if you're not go over higher order functions especially reduce because that's what we're going to use and we're going to use it in a way that's different than it's usually used okay i'm going to start with a weight because reduce does return a value so i'm going to put a weight here which will allow us to await all of the results and then i'll call reduce on the ids array that is passed in and now inside of reduce i'm going to use async again and reduce has an accumulator and then of course we'll have an id for from the ids so for each id essentially and now we'll come into the body of the function the first thing we're going to do is await the accumulator now that seems a little strange but what that does and i'll put a note here is it waits for the previous item let's say to complete so instead of accumulating numbers like if we fed at this array and it totaled up the numbers this is essentially waiting for the previous promise to resolve and then after that let's get the next item and what that is is our const post and that's going to equal a weight and then we'll call git post and pass in the id now here we can log the individual posts one at a time of course as it goes through the loop and then reduce although you don't always see it reduce also accepts an initial value that comes after the function here and what we need to put here is promise dot resolve and call that into action two with the operators and then once again just so we can see that this will all finish with the await here before we would do anything else let's go ahead and get our console log of all weight on you and let's put it underneath the reduce but it's still in our get post serialized function and i believe i replaced that up here yep so we're ready to call it i'm going to save and now let's look at the console all weight on you is at the bottom and now posts starting at the bottom with 10 counting backwards going all the way to number one so they're still serialized so let's break this down and the best way to break it down really is to remove a piece at a time so you can kind of see what it does so let's see what happens if we don't await the accumulator and i'll go ahead and save and now let's look we've got id of nine id of one id of two so they're in this strange order and look all weight on you is here in the middle so it really didn't wait so we need to use that accumulator what is happening is it's passing an unresolved promise to the accumulator and then it's going ahead and resolving and completing there so it's handing off a promise which is a strange way to wrap your head around using reduce compared to the typical example of say getting the sum of all the numbers that are in the array and then just delivering that at the end so we really need this accumulator here and we need to a wait for it to resolve now what about this promise resolve here let's just go ahead and remove it and i'll save once again and we've got the all weight on you at the end and we start with number 10 at the bottom nine counting backwards but when we get to the start there's no number one so this is the initial value and we need that initial value to get our first value back so that's why we need the promise resolved there so i think we all understand what this does when we get the post and we're logging each individual post here but then why do we have a weight here outside of reduce now remember reduce does return something it would normally be like if we fed it the array of numbers it would total all those together in the accumulator and return that so let's not await something here and just remove the await and save and see what we get in the console well we got number 10 we didn't get all weight on you though 9 eight seven six five so they're in order but i'll wait on you is at the beginning instead of the end so we need to wait here just so we can do something else afterwards after all of this is finished and that's typically what we would want to do instead of having these still processing essentially or be unresolved before we did something else now once you kind of wrap your head around how this works this might actually be your preferred way of getting serialized results from async await when you pass in an array and i have heard that people do prefer this as well because really it doesn't require as much code in a polyfill as say the well i guess i deleted it but the four of example however the four of example is very succinct as well and i believe that it's simpler to wrap your head around than this reduce solution so either would work and i just wanted to show you the different solutions you could use instead of using for each that just won't work for you when it comes to using async a weight and especially if you're requesting data from an api and you need to get that back in that specific serialized order for each is not going to help you out there remember to keep striving for progress over perfection and a little progress every day will go a very long way please give this video a like if it's helped you and thank you for watching and subscribing you're helping my channel grow have a great day and let's write more code together very soon
Info
Channel: Dave Gray
Views: 1,779
Rating: undefined out of 5
Keywords: async await with foreach is bad, async foreach, foreach async, async await, async/await, async await foreach, async for of, async for, promise.all(), promise.all, async reduce, async for loop, async foreach loop, async iterators, async await tutorial, advanced async, advanced javascript tutorial, javascript tutorial, async tutorial, async await javascript, async for loop tutorial, async reduce tutorial, promise.all tutorial, js, javascript, foreach, async await promise javascript
Id: 4lqJBBEpjRE
Channel Id: undefined
Length: 20min 8sec (1208 seconds)
Published: Tue Nov 02 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.