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

Поділитися
Вставка
  • Опубліковано 30 вер 2024

КОМЕНТАРІ • 247

  • @DaveGrayTeachesCode
    @DaveGrayTeachesCode  2 роки тому +28

    forEach is not the right choice for Async / Await code. In this tutorial, you will learn about 4 alternatives to forEach that will work when you are writing async code. If you are just starting out with Javascript, I suggest my full 8 hour Javascript tutorial here: ua-cam.com/video/EfAl9bwzVZk/v-deo.html

    • @ocoolsanni2803
      @ocoolsanni2803 2 роки тому

      Thanks for the tutorial and the info I've been looking for... I've got a question since I'm more interested in the reduce function and I'd love to try it out. How would you slower it when web scraping?? Would you use the timeout function since JavaScript doesn't have a sleep function??

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      @@ocoolsanni2803 I'm not sure how this applies to web scraping. You can use an interval in JS to time the requests if needed.

    • @ocoolsanni2803
      @ocoolsanni2803 2 роки тому

      @@DaveGrayTeachesCode Thanks for the quick responce and guidence, in an api i'm working on. Looking foward to a scrapping tutorial from you

    • @Gameplayer55055
      @Gameplayer55055 2 роки тому +1

      replacing foreach with for helped dramatically, now my entries don't hang page for 4 seconds

    • @hasithadhananjaya2806
      @hasithadhananjaya2806 2 роки тому

      dear sir, I'm begginer for JS, what is the frame work I should learn first
      NODE or REACT or else.
      Please!.

  • @urssaf343
    @urssaf343 2 роки тому +6

    Let's not forget "for await... of" loops and "generators" solution.

  • @cedigasser
    @cedigasser 2 роки тому +14

    Actualy, await Promise.all() returns an array in which the results are in the same order as the promises they're from. This is usefull if you don't need to wait after each promise but still need them in sequence.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +2

      Agreed as discussed in a few of the other comments. 💯

    • @absbica31
      @absbica31 2 роки тому

      @@DaveGrayTeachesCode does this mean line 25 at the end?

  • @Cerbeh
    @Cerbeh 2 роки тому +11

    Really cool seeing the reduce example. I recently used it myself to serialise a bulk file upload due to size limits on our API. Had never seen it before and now here you are making a video explaining it too!

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +2

      And you just described a great use case! Nice! 💯🚀

    • @maestrocode9164
      @maestrocode9164 2 роки тому

      Would a for-of loop do the same? I fail to see the difference

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      @@maestrocode9164 if you watch the video you will see the for of loop demonstrated as well.

  • @cas818028
    @cas818028 2 роки тому +1

    Devs care about other devs and their mental health. Please don’t ever use reduce this way. Thank you

  • @kumar-jatin-2000
    @kumar-jatin-2000 Рік тому +1

    Thanks Dave. I learned this lesson the hard way. I was using venom-bot and xlsx to automate sending a bunch of whatsapp messages to someone. I tried using forEach and async. That didn't end well lol.

  • @yadusolparterre
    @yadusolparterre 2 роки тому +37

    12:19 You could have refactored your code in a cleaner way:
    const posts = Promise.all(ids.map(getPost))
    No need for an async function if you are not going to await anything

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +11

      Agreed, but also noting for others reading this that await is needed before the Promise.all. Always improving - while the overall point of this video is solid, the Promise.all part is the area I would refactor. I'd still like to make a separate Promise.all video.

    • @irobot8297
      @irobot8297 11 місяців тому +1

      dude you seem junior, go back to mdn

  • @kevinbatdorf
    @kevinbatdorf 2 роки тому +5

    forEach should always be used when you can (and have side effects). It’s a declarative approach that abstracts the implementation (and optimizations) to the browser.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      Yes, forEach creates side effects. I prefer map, filter and other approaches when possible due to this. The video does not say you shouldn't use forEach. It does say it doesn't work the way many expect it to when they combine it with async requests.. and it provides a few alternatives to that approach.

    • @kevinbatdorf
      @kevinbatdorf 2 роки тому +1

      @@DaveGrayTeachesCode At the beginning you heavily imply it shouldn't ever be used. But it should actually be preferred in all cases where you would otherwise use a for loop and have side effects, except the case you demonstrated (async/await). The declarative approach lets the browser optimize the implementation.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      @@kevinbatdorf the title of the video speaks only to async/await. If it seems I imply forEach should never be used for other uses, it was not intended.

    • @BrianVanderbusch
      @BrianVanderbusch 2 роки тому

      @@DaveGrayTeachesCode just look at the poster frame for this vid... It really strongly implies "don't use for each".

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      @@BrianVanderbusch agreed. It's an attention getter and has generated a few unintended flames.

  • @dweblinveltz5035
    @dweblinveltz5035 2 роки тому +4

    I love the reduce method. So many different applications for it; having said that, I really hope not to see this usage out in the wild. The first three variations were clearer, easier to read, and more effective. One thing I really don't like is the "magic" that seems to be occurring. When I first glance at it, my first question is, "Why isn't the callback returning something?" I can imagine every new dev being thrown off by how that works.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Great comment, Dweblin! 💯

    • @quinndirks5653
      @quinndirks5653 2 роки тому

      Took me a good 5 minutes to figure it out, lol. I can definitely see how it would take a newbie much longer. It should be called "previousPromise" instead of "accumulator"... once you figure out the reason that is, then you must understand it. "async" functions return promises, even if the async function body returns undefined, either explicitiy or implicity, it will implicitly return a promise, but it will resolve to undefined, or whatever the value was that was returned by the async function body. So, in the context of the reduce method example, that means the accumulator, or "previousPromise", is always a promise that resolves to undefined, since, one, the callback was "async", meaning it returns a promise, and two, the callback did not return a value, meaning the promise will resolve to undefined. And, although the iterations are executed instantly for every id within the reduce method, which could result in asynchronous out-of-order execution when the "getPost" promises resolve at different times, it doesn't since the return value of each iteration is passed into the next iteration, and that return value (which is a promise) is awaited in the next iteration, which effectively lines the calls up and makes them wait for the previous iteration to complete before executing the next iteration. Gah, what a headache to understand. I much prefer the await promise.all solution.

  • @krishanlanka7659
    @krishanlanka7659 2 роки тому +1

    hi, can you correct my php if statement pls

  • @NguyenNguyen-ek4zq
    @NguyenNguyen-ek4zq 2 роки тому +3

    I enjoy watching the reduce alternative. However, what made me unrest there is the callback of reduce without a return statement. Turns out that with async await and without an explicit return statement, you actually implicitly return a promise resolve undefined. That could have been explained in the video. Anw, thanks for a great video.

  • @Bayo106
    @Bayo106 2 роки тому +2

    as soon as I saw this title I had an epiphany and watching it helped me solve something at work. thank you so much

  • @glennadams8833
    @glennadams8833 2 роки тому +3

    I've struggled to get serialized data from multiple async function calls and this clears up a lot. Aside from when not to use a forEach method, the gem in your lesson is going deeper into async/await and map/reduce methods. Cool!

  • @kevinbatdorf
    @kevinbatdorf 2 роки тому +1

    Never leave side effects in your reduce function. It should be a pure function that returns the accumulator. That console.log should be removed if anyone is using code from this video.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Yes, I do hope everyone understands to not leave console.log in any released code as you might see in a tutorial. You've got a long day ahead if you leave this note on any video using a console.log. Have a good day, Kevin!

    • @kevinbatdorf
      @kevinbatdorf 2 роки тому

      @@DaveGrayTeachesCode That's fair. I felt the tutorial was well made otherwise so I wanted to point out a couple things that might affect new coders. Wasn't a dig on you personally.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      @@kevinbatdorf all good my friend. I didn't think it was, but I agree console.log should be removed from any examples used from a tutorial.

  • @janjankowski8701
    @janjankowski8701 2 роки тому

    A small addition to the last serialized example:
    const getPostsSerialized = async (ids) => {
    const result = await ids.reduce(async (acc, id) => {
    const prev = await acc;
    const post = await getPost(id);
    console.log(`post id - ${id}:`, post);
    return [...prev, post];
    }, Promise.resolve([]));
    console.log("result:", result);
    }
    Allows you to receive an array of all returns by the end like promise.All()

  • @cleancode2123
    @cleancode2123 2 роки тому +2

    Nice one learned a lot !.

  • @Krenil.
    @Krenil. 2 роки тому +1

    First

  • @TheRishikesh99
    @TheRishikesh99 2 роки тому +1

    the async foreach is weird because i would not expecting ordering in code that runs ASYNChronously. If you want ordering, you need to maintain it either with promise.all and map. Foreach is nice to have when you want async side-effects

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Agreed 💯 There is an example of using Promise.all in this video along with a few other possibilities.

  • @satanacchio
    @satanacchio 2 роки тому

    I see return await, I close the video.
    It's an async function, it will wrap the return into a promise... why would you await it...

  • @user-account-not-found
    @user-account-not-found 2 роки тому

    to be fair everything about using node or JavaScript is bad. the reasons simple, system calls. any language that makes too many will never be performant under load

  • @PauloSantosk
    @PauloSantosk 2 роки тому +7

    forEach respected the await instrucion, but It was executed recursively in a more performatic way.
    If you need order, sort the results.

    • @fParad0x_
      @fParad0x_ 2 роки тому

      Do you have any info on how that works? I didn't know that forEach was executed in a different, special way.

    • @PauloSantosk
      @PauloSantosk 2 роки тому +2

      ​@@fParad0x_ it is part of the functional way of solve problems. It is executed utilizing recursion instead of a imperative instruction like the tradicional "for", for example. If you are executing asynchronous calls over a recursion loop, you cant wait the outcome in a ordered way and, "await" will not help too, because each call is in a diferent bubble of the stack and "await" will only wait in the same "bubble".
      But, you should use forEach every possible time, this video is misliding the importance of a functional way of solving the problems.

    • @BrianVanderbusch
      @BrianVanderbusch 2 роки тому

      Exactly.
      "It doesn't return them in order" means it returned them in the order they resolved, and that's what asynchronous is really about.

    • @fParad0x_
      @fParad0x_ 2 роки тому

      @@PauloSantosk Thanks for the explanation! Didn't know that.

    • @n1xx1
      @n1xx1 2 роки тому +3

      This is straight up wrong information. forEach is iterative and not recursive, as you expect for something called "for each", however it's a synchronous function, it doesn't handle anything asynchronous inside. If the function you pass to forEach returns a Promise (that is what a async function is), it doesn't wait for it. It's not about being performant or faster, it just isn't what it's meant to do.
      Also it's not about sorting the result. If you do something like:
      const data = [];
      ids.forEach(async (id) => { const res = await getPost(id); data.push(res); });
      console.log(data);
      Most probably data will be empty, because you didn't wait for any of the Promises to resolve. You probably want to go either the "reduce" or the "Promise.all with map" way, or just use a standard for loop.
      I would also like to point out that a for-of loop with awaits inside will execute the functions sequentially, waiting for the previous one to complete before starting the next one, while a
      const data = await Promise.all(ids.map(id => getPost(id));
      Will execute them all at the same time, and return when all are completed. So they are not alternatives to each other, really.

  • @caffeinated-pixels
    @caffeinated-pixels 2 роки тому +3

    Good stuff Dave. It's interesting that when you learn functional programming in JS, you are constantly told that using for loops is bad because it's imperative, but I guess that's not always the case! Anyway, that reduce method is cool.

  • @DebdutBiswasOnline
    @DebdutBiswasOnline 2 роки тому +2

    Awesome, learned a lot. I was facing exactly a same problem to asynchronously send multiple separate emails by iterating an array fetched as database result.

  • @navazsharif6783
    @navazsharif6783 2 роки тому

    Just came here after watching James Q Quick video that you are talking about at 11:00

  • @danielpeprah1577
    @danielpeprah1577 Рік тому

    Honestly, I've never been a fan of forEach. Now its totally over 😄

  • @djkos7
    @djkos7 2 роки тому +1

    Dave, seriously, you need to get known what is async callback, why sync iterator does not care about it, how promises will be resolved in the callback Q, and for sure regarding functions context, and closures.
    From other side, forEach was made with only 1 aim - apply callback function in sync way for each element in the array. That’s all, no other magic there

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      I'm not sure if you are saying I "need to get known" or you are saying I "need to learn about" what you are listing.. but my friend, I think we are talking about the same things.

  • @wojciechjarosz420
    @wojciechjarosz420 9 місяців тому

    ...and how to return fetched and resolved data from reduce function in this case?

  • @zimcoder
    @zimcoder Рік тому

    3:27 the fact that he has to explain it, means it is not easily readable code. Just keep it simple and readable.

  • @RD-jr8nv
    @RD-jr8nv Рік тому

    Reduce is so versatile, can do a million things with it. This was really neat

  • @ZhouJi
    @ZhouJi 2 роки тому

    the examples are very educational, but the conclusion "forEach is bad" sounds far-fetch. forEach is apparently the simplest way to make the thing concurrent. Or did I miss the point?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      Hi Zhou, hit and miss. Nothing wrong with using forEach most of the time. However, it is not optimal for serialized requests and responses using async/await. The title using "BAD!" should be read along with the rest of the title and probably gets a few more people to click. I've certainly had some more passionate responses from a few viewers on this one. That said, I teach beginners every semester and many try using forEach with async/await. This video provides some good alternatives.

  • @samirsamir7779
    @samirsamir7779 2 роки тому +1

    Thank you Dave for this super great dev. Channel as Well as your Teaching way .

  • @nezirdzanko6363
    @nezirdzanko6363 2 роки тому

    This is not advanced js its just terrible js advice. By not defining callbacks (which forEach is) you are not using the event loop and the multithreading provided by it. forEach is fine, sorting the Array after it is populated is the faster and more modern approach. Serialization during async function just introduces additional unecessary delay

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      If you're saying there is **never** a time you want serialized requests, your approach does work. Never say never. Also, I see beginners attempt this very approach with forEach frequently. Providing accurate alternatives is not terrible advice. Have a good day my friend.

  • @sheelaveldurai2900
    @sheelaveldurai2900 Рік тому

    how to break/exit the reduce loop and return the last value?

  • @arminmatthes
    @arminmatthes 2 роки тому

    I agree that it's important to know this beforehand, but it behaves exactly the way I'd think it should behave. To say that this should never be used in modern JavaScript is a bit dramatic. I use it all the time and I know what to expect. Oftentimes I don't need the data to be fetched in correct order.
    Besides, I think the bigger problem is that it can be hard to actually wait for all promises to resolve using forEach.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      I think this video has been misunderstood a little based on the thumbnail without some seeing it specifically addresses async / await code and serialized results. There is nothing wrong with using forEach, but many expect different results when combining forEach with async/await. This video provides those looking for a solution with alternatives that give the functionality they expected to get when using forEach.

  • @TarekFaham
    @TarekFaham 2 роки тому

    Do have tutorials about design patters in JavaScript? I'm looking for one to learn how to avoid using if then else statement using polymorphism. Can you help with this please?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      I do not at this time, but it is a good idea! Thanks for your request!

  • @AK-vx4dy
    @AK-vx4dy 2 роки тому

    Sorry to say but initial example is bad or badly explained
    forEach executes in order, but every call lives it's own live and results come randomly from api call,
    it's not bad it is how it works (but maybe it is hard to understand)
    forEach don't wait because its job is iterate over elements not wait to execute all calls.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      You're saying the same thing I demonstrated. I don't expect everyone to like my explanations, no worries.

  • @repenning1
    @repenning1 Рік тому

    not sure why you would advocate using reduce over for_of. The main point of reduce is to bubble some computation such as a number accumulator not to just to chain promises. Of course you can serialize this kind of operation using reduce but this is unnecessarily complex because you are not reducing return values from async function but only promises. Makes more sense to let the for_of do this.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  Рік тому

      It's been awhile but I don't think I did advocate for anything over for_of. I think I showed several examples to use instead of for_each. I don't think I declared one example was above the others.

  • @atgaming263
    @atgaming263 2 роки тому

    This forEach problem was only in JS or in all programming language that has forEach function ?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      I cannot speak to all programming languages, but in JS when you need to have serialized requests & responses, this provides some alternatives.

  • @vitason100
    @vitason100 2 роки тому

    Hi Dave,
    Thank for this tutorial !!!
    Can you explain how we can handle error in this way, thank you.

  • @Ginold
    @Ginold 2 роки тому

    i did not understand WHY a forEach loop does not allow for async promise whereas for loop does?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      I don't know if I can explain it here better than the video, but forEach wasn't really designed for promises. It does not wait on them to fulfill or reject. I show some alternatives in this video that will await the response and allow you to keep the results serialized.

  • @basilistigris640
    @basilistigris640 2 роки тому +1

    one more masterpiece Javascript video lesson, very professional and perfectly explained lessons in javascript, very orginized channel, i learned a lot, thank you Dave Gray!

  • @DM-pg4iv
    @DM-pg4iv 2 роки тому

    This is pretty cool. So is forEach just nlt a good idea ib general? Let's just say a regular func that you want to go through data. Is for of better?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Nothing wrong with using forEach for many needs, but if you desire a serialized response to requests, it is not the one to choose.

  • @AntonioSantos-ve6zv
    @AntonioSantos-ve6zv 2 роки тому +1

    Kind of advanced for me at this point, but it's put so clearly I've learned a lot. Thanks!

  • @autobot021
    @autobot021 2 роки тому

    the promise.all method does not seem to work for me

  • @john_paul_r
    @john_paul_r 2 роки тому

    Worth noting that Promise.all will maintain the order that you pass the promises to it. The promises can complete in any order, but the returned results will always match the order of the passed array of promises.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      Agreed, and noted in some other comment discussions, too. The array holds the order. Thanks! 🙏💯

  • @pellax
    @pellax 2 роки тому

    Trying to improve my Javascript, great video, subscribed

  • @Jay-dq5mq
    @Jay-dq5mq 2 роки тому

    why not consider using bluebird.map() instead?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      I provided some alternatives in the video, but not all alternatives. If used correctly, map() will work. So will reduce(), flatMap(), and reduceRight().

  • @benarcher372
    @benarcher372 2 роки тому +1

    "To get the job done". Most of the time that's all that matters. Thank you Dave for all your great JavaScript tutorials.

  • @TheDaviddoodles
    @TheDaviddoodles 2 роки тому

    Hey Dave would you do some videos about Svelte I really love the way explain things

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Thank you for the request! It may be awhile, but I'd like to do something with Svelte, too!

  • @MaksymMinenko
    @MaksymMinenko 2 роки тому

    12:40 The white screen of death. 😀

  • @rajapboyev3928
    @rajapboyev3928 2 роки тому +1

    Big thanks to Dave Gray, very good explanation😃

  • @dcvsling
    @dcvsling 2 роки тому

    why use wrong practice to say something is bad ?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      You may have preferred that I say "it is the wrong choice". Either way, I see beginner students attempt it this way all the time, and it is a good exercise to show why they should not and what alternatives could work for them.

  • @jiweihe3413
    @jiweihe3413 2 роки тому

    Thanks for the interesting video! I just have a naïve question. 3:10 I thought hoisting does not work for arrow functions, but it works for the useforEach() arrow function. Just curious why.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      That's a great question! I must have the initApp function defined before the event listener that calls it, but because I'm calling initApp with an event listener, it allows me to define everything else below. If I just called initApp() without the listener, this would not work. The DOMContentLoaded event has to fire before initApp is called. A similar explanation on StackOverflow: stackoverflow.com/questions/72235699/how-does-function-within-addeventlistener-gets-hoisted

    • @jiweihe3413
      @jiweihe3413 2 роки тому

      @@DaveGrayTeachesCode I see. That makes sense! Thank you so much!

  • @focusiam2027
    @focusiam2027 Рік тому

    Road to 500k, congrats for the 100k🎉🎉🎉🎉

  • @saitejagatadi9711
    @saitejagatadi9711 2 роки тому

    13:13
    Dave, The mobile mode was on in browser. Not sure it was intentional 😄

  • @MichaelMcGreal
    @MichaelMcGreal Рік тому

    Nice use of reduce!

  • @wagiewojak
    @wagiewojak 2 роки тому

    You put quite alot of unessecary async's

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      I count two. I will await your refactor. Please share in a Github gist.

  • @decay6591
    @decay6591 2 роки тому

    fixed redux thunk bug. appreciate. got sub

  • @marufnajm7453
    @marufnajm7453 2 роки тому

    Very interesting

  • @thecutedreamkostasp.4449
    @thecutedreamkostasp.4449 2 роки тому

    Thx God there are better programmers than me. They make me bettter. I appreciate this sir.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      I'd suggest avoiding thoughts about who is better or not. I always say keep striving for progress. A little bit every day is the goal. 💯

  • @valenciawalker6498
    @valenciawalker6498 5 місяців тому

    Tbank you!

  • @LordValtrius
    @LordValtrius 2 роки тому

    There's an issue with your reduce method. `await acc` isn't doing anything because you're not returning the promise. It's getting resolved instantly and moving onto the `getPost` which it is awaiting.
    Additionally you shouldn't use await within a loop (I never use it outside of a loop) because you have to wait for it to finish before moving onto the next iteration. Use `then` instead (which gets returned, obviously) so each request is "concurrent" but resolves in order.
    Also James Q Quick's code will also resolve in the correct order everytime as Promise.all returns an array of responses in the order the promises were passed in and would also be concurrent.
    Im replying on my phone but if you want an example of the reduce-then method just give me a shout.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Wow, I appreciate the time it took you to give such a detailed response. Thanks! Good discussion items even if we do not agree on all 😀
      If this video wasn't about receiving a serialized response, I'd agree that 'await acc' isn't doing much in the reduce solution... but it very much is. If you remove it, your response results will not be in order (serialized). Maybe I should have said what my comment in the code says which is "waits for the previous item to complete" instead of saying it resolved.. but the concept is clear.
      I'd like to see some references on not using await in preference of .then() in a loop. I believe await is legitimate when used appropriately.
      I do agree on the Promise.all as I have discussed with others in these comments, too. My example does work as shown for Promise.all. However, I said it may not provide serialized results, but it indeed consistently does.

    • @LordValtrius
      @LordValtrius 2 роки тому

      @@DaveGrayTeachesCode Hi. I wasn't sure if you would see my comment, never mind reply to it so thanks for that.
      You're right in that `await acc` is necessary for the loop to wait for the previous iteration. I didn't realise a promise is always returned from an async function even when not explicitly returned, did I mention I don't use async/await 🤣
      I still don't think the waterfall approach is best for ajax requests. Here's my concurrent solution that acts on the data in a serialised way, reduce-ing the overall time taken. It's the best of both worlds from James Q Quick and your serialised approach since it can run on the data available while it waits for the next ajax req to finish.
      codesandbox.io/s/elegant-wiles-tvnqk6?file=/src/index.js

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      @@LordValtrius I appreciate the reply - and great share! Thank you! 💯🚀

  • @ScriptRaccoon
    @ScriptRaccoon 2 роки тому +4

    I really like the concurrent version since it is faster. When we care about the order of posts, we could just sort them after we have fetched them, right? I am not sure though if this is still faster than the serialized version then, it probably depends on the number of posts we fetch.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Nailed it here. It's going to depend on the number fetched and if you are adding the results to specific serialized data after receiving it. Several considerations. 💯

  • @TheYinyangman
    @TheYinyangman 2 роки тому

    Why do the higher order array methods not always return serialised data ?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Specifically, this applies to responses you await with async code. Some of the higher order methods are not designed to await responses. For example, forEach has no return. The response is not guaranteed to come back in the order the request was sent either. Some of the alternatives presented here help keep the responses received in order.

  • @designcoded7585
    @designcoded7585 2 роки тому

    most of the frameworks and peoples are using .map() only both for iteration like for loop os even for returing from the helper function , so far map is the popular way , so there no suprise , but for just practising we can use forEach() its nice

  • @randomnobody660
    @randomnobody660 2 роки тому

    I'm not sure I see the issue? For each element in the array you asynchronously did some stuff to it (in this case called some api then logged the result), so of course each operation doesn't, and imo shouldn't, wait for the previous one to finish no? In fact why are we awaiting each fetch in the for loop anyways?
    I don't even understand what's in the video's opinion the better alternative; imo it would be more counter intuitive and less useful if you couldn't do async operations with foreach loops. Is the point just that foreach is a special case of map? I mean sure, but they express different intent (to the programmer/reader), which imo is important. Most branching statements are just conditional gotos with maybe some stack pushing and poping, yet people still somewhat pick and choose for this reason.
    I think it's quite expressive that you use reduce if you want each item to depend on the last, map if each item is independent, and foreach if the prior is true but you also don't care about return values.
    I'm sure there are legitimate gripes with foreach, but I didn't personally find this particular one convincing.
    Also also, if you really want it to "return" something you could always assign the promise somewhere then await outside no?

    • @randomnobody660
      @randomnobody660 2 роки тому

      ok, so those are all talked about in the video as alternatives but again, what's the advantage of switching? Still not sure I understand.

    • @randomnobody660
      @randomnobody660 2 роки тому

      plz no delete again...but foreach can also return like so:
      ```
      const getPost = async id => (await fetch(funnyURL+ id)).json(); // i suspect the url is why youtube keeps deleting this
      const getPostsForEach = async ids => {
      let ret = [];
      ids.forEach((id, i) => ret[i] = getPost(id).then(console.log));
      await Promise.all(ret);
      console.log('i\'m waiting fine?');
      }
      ```
      Also, like another gent mentioned, no need to async if you aren't awaiting. Also also, no need to await right before a return.
      In the case of getPost, the caller is going to get a promise if the caller doesn't await, or the promise if it does, whether you add that 2nd await or not.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Thanks for all the input. Yes, all alternatives listed. Far too often I see beginners use forEach while awaiting promises and expect to get the results back in the order of the requests. The video points out that is not going to happen. For serialized results, the alternatives I've provided - and others have added in the comments - are better choices. The thumbnail for the video has brought out some stronger opinions, and at the same time garnered a few more views.

  • @AK-vx4dy
    @AK-vx4dy 2 роки тому

    .map guaraintes order!!!
    you get promises in order of ids
    when these promises retrurn value it's random, but Promise.all returns when ALL return values (or first be rejected (error)),
    then you console.log whole array then they will be ordered

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Yes, as noted in some of the other comment discussions I've had. Map and a few other methods do work.

  • @melpacheco9288
    @melpacheco9288 Рік тому

    Masterful!

  • @tyler8995
    @tyler8995 Рік тому

    What's the extension that gives that line between your opening and closing braces?

  • @shrooobdude
    @shrooobdude 2 роки тому +1

    I'm a bit late to this video, but Promise.all does retain the order. Think of it as passing an array of promises, when each promise resolves they are transformed into their resolved value, but their position in the array does not change. So while they resolve at different times, the order is retained. I hope this makes sense :)

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      It does make sense. I don't think I said Promise.all wouldn't work? It's been months so I would have to watch it myself 😃

    • @shrooobdude
      @shrooobdude 2 роки тому

      @@DaveGrayTeachesCode oh no you never said Promise.all wouldn't work - just that the order may not be retained 😁

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      @@shrooobdude ah I see! I'd like to make a separate Promise.all video as well.

  • @Dibakash
    @Dibakash 2 роки тому

    Amazing.

  • @dheerajs2838
    @dheerajs2838 2 роки тому

    this was agreat tutorial .. impressive

  • @oksanakobyliatska6822
    @oksanakobyliatska6822 2 роки тому

    Thanks a lot, that was very helpful!

  • @SkyrimBeast
    @SkyrimBeast 2 роки тому

    Another great video Dave, many thanks. How could we go about fetching data from 2 API endpoints where the second API call depends on JSON data from the first API endpoint? Maybe this could be a future tutorial if you're so inclined.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Good question and request! This requires waiting for one response before moving on to the next. I would use async / await and confirm success before moving to the next. In React, we use different states like isLoading, isSuccess, and isError to trigger different page renders.

  • @luiizmorales316
    @luiizmorales316 2 роки тому

    thanks bro... good video 👍🏽

  • @caiofdacosta
    @caiofdacosta 2 роки тому

    That . map was my favorite

  • @rike7777
    @rike7777 2 роки тому +1

    Very enlightening lesson. I really liked to see the difference between the serialized and the concurrent versions, as well as the use of reduce to solve the problem, although it is difficult to grasp at first. By the way, I also liked you VS Code Theme, which is easy on the eyes. Can you please tell me what it is? Thank you!

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      Glad you found it helpful. And yes, I just switched to this theme and really like it. It's the Github Theme. Several dark modes to choose from.

  • @MaksymMinenko
    @MaksymMinenko 2 роки тому

    So, does the Promise.all version (getPostsConcurrently) execute the fetch operations concurrently, waits for all of them to complete and then kind of sorts the results in the initial order (of the elements in the array)?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Going by memory here, but I believe the Promise.all version also used array.map(). Some discussion here in the comments on this solution, and even though I said it may not keep the order during the video, I now agree that it will keep the order based on map(). Therefore, your explanation is pretty much spot on except for the "sorts the results" part because it keeps them in order without further sorting needed.

  • @hv7460
    @hv7460 2 роки тому

    Thanks a lot....I was yesterday calling Restendpoint1 inside foreach and Restendpoint2 outside foreach.... and the requirement was that Restendpoint1 should be called before Restendpoint2 ...but could not figure out this weird thing about foreach.... Thanks for sharing this...

  • @show_me_the_moneyy
    @show_me_the_moneyy Рік тому

    Good one - reduce was a mind bender - I wonder if reduce is preferable for something like this because readability is impacted

  • @dindoleonard
    @dindoleonard 2 роки тому

    So glad i stumbled into this gold mine of a video

  • @ericapinheiro9891
    @ericapinheiro9891 2 роки тому

    Amazing reducing js!

  • @FullStackDevGreg
    @FullStackDevGreg Рік тому

    Thankyou very much sure

  • @mohamedamineboukraia5528
    @mohamedamineboukraia5528 2 роки тому

    What a great tutorial Dave!!

  • @mohamedabdelkefi9947
    @mohamedabdelkefi9947 2 роки тому

    thank you you saved my day

  • @polinafeterman5057
    @polinafeterman5057 2 роки тому

    Thank you for this explanation. Very clear and useful! Could you please tell me what is this extension that you called Dev Tools For Chrome? I can't find it in VS Code... Thank you!

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      It is built into Chrome already. No extension needed. Right click your web page and choose "Inspect" from the menu to open dev tools. Or press Ctrl+Shift+I to open.

  • @arminmatthes
    @arminmatthes 2 роки тому

    What I don't like about the reduce example is that you can't really return the resulting values as an array because you've put the promise into the accumulator... You don't always just want to log the result in the callback.
    You could pass in an object {lastPromise: null, result: []} and then adapt your code accordingly - if lastPromise is null, just dispatch the first Promise, then skip ahead to the next call. After awaiting the promise, push the result onto acc.result.
    Voila - you can have the cake and eat it, too.
    I just made this up without actually testing it, but it should work.

  • @gradar7891
    @gradar7891 2 роки тому

    Most informative tutorial I’ve ever encountered for recent years 😄

  • @debjyotibanerjee9846
    @debjyotibanerjee9846 2 роки тому

    Wonderful video..

  • @lalitpatil7972
    @lalitpatil7972 2 роки тому

    2 days before I was struggling with this forEach with async issue and today I saw your video. Saved my day.
    Thank you.

  • @subhajitpanja1353
    @subhajitpanja1353 2 роки тому

    Sir, you are the best JS teacher to me.
    Thank you for your efforts in making these videos. When I watch your video concept of that tropic getting clear.
    I have already requested you to make a video on React testing.
    That subject I want to learn from you.

  • @alexanderkomanov4151
    @alexanderkomanov4151 2 роки тому

    I really happy that I found your channel. Your manner of explanation is the one of the best I saw. Thanks a lot for the content! Describe and big like from my side!

  • @manujohn5346
    @manujohn5346 2 роки тому

    Wow...very helpful. Wish I had seen this few months back. Would have saved me a ton of time😅

  • @GssGPL
    @GssGPL 2 роки тому

    dave you are the og

  • @alexalannunes
    @alexalannunes 2 роки тому

    Fantastic🥳🥳🥳🥳

  • @CesarScur
    @CesarScur 2 роки тому

    The "problem" is not with the foreach concept. It is with the closure implementation of this foreach. Foreach is not evil.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому

      Never said it was. This video is for those who try to use forEach when they want a serialized response.

  • @brightmatter
    @brightmatter 2 роки тому

    Concurrent also has a bigger issue. If you attempt to do too many concurrent operations at once you can begin quasi-blocking other operations because you are clogging the thread with to many requests for work at once. The way to handle this is designing a limited concurrent operation stack/queue. I've made them in the past, but I used callbacks, timers, and recursion. Modern implementations would likely use promises, and I'd love to see how that is done.

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +1

      In this video, I demonstrate several alternatives that do indeed work by awaiting promises to fulfill. 💯

  • @0xAndy
    @0xAndy 2 роки тому

    Thank you so much. I'm a new subscriber and really enjoy the channel so far.

  • @kirindev
    @kirindev Рік тому

    thank you.

  • @Shubhaw
    @Shubhaw 2 роки тому

    This is the exact same problem I faced last week in my office. Thanks for the solution. Although I would like to know why "await" doesn't work inside the forEach method body. Any links where I can read it in more depth?

    • @DaveGrayTeachesCode
      @DaveGrayTeachesCode  2 роки тому +2

      You're welcome. Yes, go down to the 2nd blue block on this page where it says "Note: forEach expects a synchronous function." developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

    • @Shubhaw
      @Shubhaw 2 роки тому

      @@DaveGrayTeachesCode Thanks again! :)