Managing Promise Concurrency in JavaScript

Поделиться
HTML-код
  • Опубликовано: 14 фев 2024
  • Check out the code for this video here: gist.github.com/andrew8088/7e...
    My Links
    shaky.sh
    shaky.sh/tools
    #programming #coding #javascript #promises #concurrency
    #frontenddeveloper #backenddeveloper #softwareengineer #softwareengineering #softwaredevelopment
  • НаукаНаука

Комментарии • 54

  • @adiadiadi
    @adiadiadi 4 месяца назад +19

    Selfishly, I prefer when you cover intermediate/advanced/niche topics like these as there's already a deluge of beginner-level content. But I get that beginner content can draw more views which would yield a higher return on the effort you put it. I don't mind the occasional TypeScript video either. Honestly man, you do you. I find your videos to be a cut above the rest generally.

  • @senshiougonno7017
    @senshiougonno7017 4 месяца назад +9

    to answer your question
    YES
    demo-ing how to resolve some of the problems that you or people you know might have encountered is probably very helpful for a lot of us out there
    Keep it up !

  • @KubaBogaczewicz
    @KubaBogaczewicz 4 месяца назад +18

    Very nice video, but you have a race condition. Look at that code:
    let a = [];
    a[2] = "hello";
    console.log(a.length); // === 3
    Your overall mapPromises does not resolve when all promises resolve, it resolves when the last promise resolves (function next, line 20).

    • @andrew-burgess
      @andrew-burgess  4 месяца назад +3

      ooooh, that's a really good catch! I guess the simplest way to solve it is with `let completed = 0`, increment in the final `then`, and check that `completed === args.length`. Thanks!

    • @fardolieri
      @fardolieri 4 месяца назад +2

      Another quick fix could be to check for `Object.keys(results).length` instead of `results.length`. But the `let completed = 0` approach is probably is more readable.

    • @andrew-burgess
      @andrew-burgess  4 месяца назад +1

      yeah that works too. I don't love the extra unnecessary iteration of results, though.

  • @shivankmittal2226
    @shivankmittal2226 4 месяца назад +2

    This is exactly what kind of videos i am looking for. Getting to know how we can use them properly

  • @Jelle-DV
    @Jelle-DV 4 месяца назад

    Awesome! Maybe you could start the video with a quick demonstration of how your end solution can be used/called, and then start building it

  • @MichiganTypeScript
    @MichiganTypeScript 4 месяца назад +4

    this is a really cool concept! glad to have watched to the end because the whole time it seemed like there _must_ already bee some API for this, but yours is unique. It's pretty neat how you managed to do it so succinctly, too!

    • @mazwrld
      @mazwrld 4 месяца назад

      i agree

  • @capability-snob
    @capability-snob 4 месяца назад +1

    Your .then() is always run on an almost empty stack - this is part of the A+ spec and reflects the original semantics in E. The only thing there is a resolver, but the promise itself is unused, so it's not that different to explicitly using setImmediate afaict.

  • @lenaggar
    @lenaggar 2 месяца назад

    first of all YES!
    second, I have a comment on the implementation, there's a possibility (in the case that the concurrency limit is 3) that either one of or both of the 2 jobs before the last one finish after the last one does; in this case the returned results list will have their corresponding values in the results array as undefined, and also callback will be called more than one time. possible solutions I could think of:
    1- do a filter operation on existence of values before checking for equality with the inputs array length; else if (results.filter(Boolean).length == inputs.length)
    2- use a Map keys as the index of the result in the array and values as the result; verify using map.size rather than results.length; then when you finally resolve, you can map it into an array again

    • @lenaggar
      @lenaggar 2 месяца назад

      Oh! I just watched your next video, your solution using the `settled` counter is much simpler. Thank you for that one

  • @edgeeffect
    @edgeeffect 8 дней назад

    As long as it's intermediate or advanced level... I like a nice mixture of TypeScript and JavaScript.

  • @Shr11mp
    @Shr11mp 4 месяца назад

    Yes, this was an awesome video! I'd love to see more of this.

  • @user-jl3sl3su1b
    @user-jl3sl3su1b 4 месяца назад

    Love your videos, there is always something to learn from you. Keep doing it

  • @Haawkyy
    @Haawkyy 4 месяца назад

    Awesome! Nice feature to work on; executed quickly and with clear explanations. Thanks a lot for this one (and yes, please, continue on this path).

  • @reverser41
    @reverser41 4 месяца назад

    love any kind of videos that you make.

  • @rendezone
    @rendezone 4 месяца назад

    It’s better to use finally than then in case catch throws, but in your case then will work. I think finally has better semantics for what you want to convey

  • @lacherolachero9409
    @lacherolachero9409 4 месяца назад

    Absolutely more of this advanced stuff!

  • @fagnersales532
    @fagnersales532 4 месяца назад

    I actually loved it, I'd appreciate to see it again but typescript is also fun as well.

  •  4 месяца назад

    TypeScript and JavaScript videos are awesome!! Please go ahead with both types!!

  • @rockNbrain
    @rockNbrain 4 месяца назад +1

    Nice job dude 🎉

  • @raflidewanto
    @raflidewanto 4 месяца назад

    Would love to see more of this👍

  • @dimitro.cardellini
    @dimitro.cardellini 4 месяца назад +1

    Pretty nice.
    Small comment. The function is not universal and difficult to describe types for it.
    Here is the typed one:
    type Task = () => Promise;
    type TaskResult = T extends Task ? R : never;
    const concurrentAllSettled =
    (concurrency: number, ...tasks: T): Promise => new Promise((resolve) => {
    const count = tasks.length;
    const results = Array(count).fill(undefined) as { // PACKED_OBJECTS
    [K in keyof T]: PromiseSettledResult
    };
    let current = 0;
    let settled = 0;
    const next = () => {
    if (settled === count) { resolve(results); return ; }
    const index = current++;
    const task = tasks[index];
    task()
    .then(
    (value) => { results[index] = { status: "fulfilled", value }; },
    (reason) => { results[index] = { status: "rejected", reason }; },
    ).then(
    () => { settled += 1; next(); },
    );
    };
    while (concurrency-- > 0) next();
    });

  • @cesardiaz1925
    @cesardiaz1925 4 месяца назад

    Use of setImmediate was beautiful. Introduced me it so thanks

  • @tthiagolino8
    @tthiagolino8 4 месяца назад

    Love both kinds of videos

  • @user-ok9zi7tr2l
    @user-ok9zi7tr2l 4 месяца назад

    this kind of video is really cool

  • @fardolieri
    @fardolieri 4 месяца назад +2

    setTimeout is a drop-in replacement for setImmediate and has browser support. If not given a delay parameter it behaves as if passed a 0, so just like setImmediate.
    But in your case I think it would be fine dropping it altogether. I can't see the drawback of simply using `.then(next)`. They are not really bound to each other because your next function never returns anything.

  • @nazarshvets7501
    @nazarshvets7501 4 месяца назад +1

    I`m really curious about that call stack situation. How is that even a thing? Actually have no clue how call-stack(s?) works

  • @sidwebworks9871
    @sidwebworks9871 4 месяца назад

    setImmediate unlike the name won’t run “as soon as possible” instead it will enqueue the task at the end of the current loop iteration.
    If you need something to execute in the same tick or “as soon as possible” use process.nextTick instead
    The naming is messed up IK but its just a little node gotcha

  • @dasten123
    @dasten123 4 месяца назад

    I'm in for both kinds of videos, or different ones too :)

  • @PickleRiiiiiiick
    @PickleRiiiiiiick 4 месяца назад

    Both types of videos are good. Mix it up!

  • @awekeningbro1207
    @awekeningbro1207 4 месяца назад

    what font are you using in the IDE?

  • @Matt23488
    @Matt23488 4 месяца назад

    You seem to be pretty good about making videos on interesting topics, TypeScript or not. So in my opinion just keep doing what you're doing, if you find something you think is worth making a video about, it probably is.

  • @UserUnknown6
    @UserUnknown6 4 месяца назад

    Won't wrapping the contents of the mapPromises function in a promise do the same as using this new, experimental feature? Or am i missing something?

  • @evandroLG2
    @evandroLG2 4 месяца назад

    Cool video! Thanks!
    Just out of curiosity: I solved this same problem during a coding interview at Uber, in 2021.

    • @lenaggar
      @lenaggar 2 месяца назад

      that's funny; I interviewed at Uber last year and got the same problem during my interview but it was using callbacks instead of promises

  • @hut_fire1490
    @hut_fire1490 4 месяца назад

    Hi andrew love your videos ! Btw can you make a video about map in javascript such when we should use it instead of plain object. Ty ❤

    • @Anshucodes
      @Anshucodes 4 месяца назад

      map have better performance , !!

  • @proesus7446
    @proesus7446 4 месяца назад

    does the index start at 1 since cursor is incremented?

  • @mazwrld
    @mazwrld 4 месяца назад

    what’s that font??

  • @danel1922
    @danel1922 4 месяца назад

    atm i'm doing only django/oscar work, man i miss js. to answer your question: yes, more please!

  • @mrlectus
    @mrlectus 4 месяца назад

    Can generators be used here?

  • @studiowebselect
    @studiowebselect 4 месяца назад

    P-map for node20 ;)

  • @PaulSebastianM
    @PaulSebastianM 4 месяца назад +1

    You're not implementing the concurrency flag like you said you would. It's acting more like a count of promises to start, and not an an amount of promises to schedule at a time... correct me if I understood incorrectly.

  • @malvoliosf
    @malvoliosf 2 месяца назад

    There is a huge bug in your code!
    The results are returned in the order they were resolved, NOT the order they appeared in the original args array. Make a function that has the functionality “given n, wait 10-n seconds then return n” and run it with an array 0 through 9 and a concurrency of 10. The numbers will be returned in reverse order.

  • @user-ec7np3ef9h
    @user-ec7np3ef9h 4 месяца назад

    what about both Andrew 😄

  • @inuoshios
    @inuoshios 4 месяца назад

    what is the name of your font?

  • @yunyang6267
    @yunyang6267 4 месяца назад

    you look like the guy from Planetscale teaching database so much, it's confusing

    • @daleryanaldover6545
      @daleryanaldover6545 4 месяца назад

      it also doesn't help that they both have square glasses 😂

  • @eljay3762
    @eljay3762 4 месяца назад

    Both .catch(onRejected) [aka .then(undefined, onRejected)] and .finally(onFinally) [aka .then(onFinally, onFinally)] are simple aliases of .then(onFulfilled, onRejected).
    So with that in mind, your code would be better structured as .then(onFulfilled, onRejected).then(onFinally) rather than the current .then(onFulfilled).catch(onRejected).finally(onFinally).
    I would highly recommend reading the MDN docs on .then(), you should find them informative.