JavaScript’s Deferred Promise Pattern

แชร์
ฝัง
  • เผยแพร่เมื่อ 25 ส.ค. 2024
  • The deferred pattern is a great way to add new flexibility to the way you use promises.
    Looking for more TypeScript goodness? Check out my blog post on better utility functions with TS Generics: shaky.sh/ts-ge...
    My Links
    shaky.sh
    shaky.sh/tools

ความคิดเห็น • 62

  • @andrew-burgess
    @andrew-burgess  ปีที่แล้ว +1

    If you’ve used the deferred pattern before, share your use case in a comment!

  • @samuelgunter
    @samuelgunter ปีที่แล้ว +10

    my initial thought was "what that's stupid" but through the example I thought "yeah that can be useful". this was because the way it originally seemed was that you returned the deferred object itself, and the caller of the function got back the promise as well as a way to resolve and a way to reject, but since you just return the promise it's just a more compact way to do it than you would with a promise

  • @kalelsoffspring
    @kalelsoffspring ปีที่แล้ว +11

    I'm most a backend dev, but this is super handy even for certain asynchronous operations *I* would do. Love it!

  • @dimitrimitropoulos
    @dimitrimitropoulos ปีที่แล้ว +10

    it'd be super cool to see more about what you're up to with the audio APIs!

    • @deadlyecho
      @deadlyecho ปีที่แล้ว

      Currently implementing a side project using OpenAI and Audio APIs, Siri like😂😂

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว

      Right now, just playing around to learn the APIs. Wanna learn more about how to process audio. But if I come up with any small projects, I’ll be sure to share them!

  • @bahmanasheghi
    @bahmanasheghi ปีที่แล้ว

    this is great, I used to to create a chainable promise returning Api call!

  • @kerrykreiter445
    @kerrykreiter445 11 หลายเดือนก่อน

    Thank you so much for helping beginners advance their level of JS knowledge. Your top-level tutorials are always presented so clearly and concisely that even I can benefit.

  • @625dennisk
    @625dennisk ปีที่แล้ว

    Super useful pattern for mocked promises in tests. Gives test full control of promise resolution or rejection

  • @tempaccount8256
    @tempaccount8256 ปีที่แล้ว +6

    Hi @Andrew. This was a great topic and you did teach us well, but if you give us more use case for this, it would be better.

  • @oscardasilva971
    @oscardasilva971 ปีที่แล้ว +1

    Wow thank you, I wish you post more advanced content like this.

  • @hideinbush0
    @hideinbush0 ปีที่แล้ว

    Would love seeming more patterns videos like this!

  • @Luxcium
    @Luxcium ปีที่แล้ว

    It's unusual for me to a actually use the code from a video including the most interesting and I have been learning a lot from many but it is the second time I am using the code from your video to play with it and such

  • @EthanStandel
    @EthanStandel ปีที่แล้ว +9

    I think that pattern makes your code way less readable when you could just say
    const asyncBlob = new Promise(resolve => ...)
    and wrap it around the media recorder stop event listener and then return asyncBlob in the returned function. I think using a plain promise here creates a more distinct point of definition for how the value of the blob gets resolved and what logic is required to resolve it.
    This just feels like abstraction for the purpose of abstraction.

    • @Tony-bu1rj
      @Tony-bu1rj ปีที่แล้ว

      Bro you missed the stop operation from the caller.
      const endRecording = recordStreamAsBlob(…)
      ….
      const blob = await endRecording()

    • @EthanStandel
      @EthanStandel ปีที่แล้ว +4

      @@Tony-bu1rj No I didn't 🤨 Here's the full implementation without any need for a promise wrapper
      export function recordStreamAsBlob(stream: MediaStream) {
      const mediaRecorder = new MediaRecorder(stream);
      const chunks: Array = [];
      mediaRecorder.addEventListener("dataavailable", (e) => {
      chunks.push(e.data);
      })
      const asyncBlob = new Promise(resolve => {
      mediaRecorder.addEventListener("stop", () => {
      const blob = new Blob(chunks, { type: "audio/ogg; codecs=opus" });
      resolve(blob);
      })
      })
      mediaRecorder.start();
      return () => {
      mediaRecorder.stop();
      return asyncBlob;
      }
      }
      // now that can be called the same way
      const endRecording = recordStreamAsBlob(stream);
      const blob = await endRecording();

  • @maryburgess4040
    @maryburgess4040 ปีที่แล้ว +1

    Way to go, Son!

  • @deamorta6117
    @deamorta6117 ปีที่แล้ว

    This is really cool. Please more patterns!!

  • @thi-m10
    @thi-m10 ปีที่แล้ว

    Great video. I've never seen this pattern before. Thank you for sharing!

  • @magicbob8
    @magicbob8 ปีที่แล้ว

    This is super cool. Will be looking for ways to use it going forward!

  • @sergiomorenosuay3030
    @sergiomorenosuay3030 ปีที่แล้ว

    I really like this patterns!

  • @peteradam4740
    @peteradam4740 ปีที่แล้ว

    Great video🎉

  • @darealmexury
    @darealmexury ปีที่แล้ว

    I must say I never really cared about TypeScript that much, but the way you explain TypeScript and the possibilities / ease of use is making me interested.

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว +1

      Huge compliment, thanks! I’m curious, what has made you dismiss TS in the past?

    • @darealmexury
      @darealmexury ปีที่แล้ว +1

      ​@@andrew-burgess TypeScript has always seemed like a thing that was great, but not necessary if you're just making hobby projects. I've recently started making websites "professionally", and currently my only reason why I haven't used it before is lack of time due to school and my boss doesn't want me to spend time on TypeScript. Right now at least, since we have a lot of open projects at the moment. But maybe when it's slow at work I will check it out, and once I have a bit more freetime :)

    • @abdellatifsraiti2032
      @abdellatifsraiti2032 ปีที่แล้ว

      @@darealmexury the funny thing is in the long run typescript is going to gain you time by avoiding stupid error that are completely missable with plain JS

  • @JavierHarford
    @JavierHarford ปีที่แล้ว

    I remember I first saw the blob API, I was so confused

  • @lierdakil
    @lierdakil ปีที่แล้ว +1

    There is a simple enough way to do this without this pattern, just wrap setting up the event handlers inside the promise, bind it to a variable, then start, and return your function returning the promise. Not to say this pattern isn't useful, but in my experience it's very occasionally useful for very convoluted async control flows.

  • @seannewell397
    @seannewell397 ปีที่แล้ว +1

    Yeah deferred rocks, it essentially encapsulates in a reusable way whenever I've done new Promise(.. and captures the resolve function by binding it to an outer variable. Deferred is way less to reason about.

  • @Nonsense116
    @Nonsense116 ปีที่แล้ว

    great stuff!

  • @helsontaveras7961
    @helsontaveras7961 ปีที่แล้ว +1

    Love this pattern! I’m using something very similar with the spawn child API to capture the exit event. I need to know the return code, and that’s only available on exit callback.

  • @lacherolachero9409
    @lacherolachero9409 ปีที่แล้ว

    Wow so cool!

  • @45g4rerf45f45
    @45g4rerf45f45 ปีที่แล้ว +1

    I don't get it, where did you get that "Deferred" type from?

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว +1

      The code itself, I just wrote; it’s, like, 8 lines. The pattern has been around for a long time, not something I came up with. I know it was popular with jQuery back in the day, but it’s still a useful pattern in many cases. I’m gonna see if I can come up with a list of ways to use it

    • @45g4rerf45f45
      @45g4rerf45f45 ปีที่แล้ว +1

      Somehow I totally missed the first part of the video (-‸ლ)

  • @AlexanderCerutti
    @AlexanderCerutti ปีที่แล้ว +1

    I find the deferred promises a very very dirty way to achieve things. It feels so bad to me to expose the internals of promise (resolve and reject). I am the idea (and I actually been able to make the same thing with) that if ones can master thenables, it will be able to achieve a more readable / cleaner code that do not expose Promises internals. Also, await supports thenables as well, so a 'then' method gets called when used with await.

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว

      Interesting take, thanks for sharing! I’m not familiar with thenables, but I’m gonna check them out.

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว +1

      Okay, I looked into thenables, looks like we’re mainly talking about normal promises 👍. Curious to see how you would refactor this example to use a regular promise and not Deferred.
      But also, within the context of the `recordStreamAsBlob` function example, the logic inside it will always have to directly access resolve and reject, even if somehow you can put it all inside a Promise callback. So I don’t really agree that you aren’t exposing the Promise internals. Inside, you’ll have access to the promise as well as its resolve and reject functions, and outside you’ll just have access to the promise you return.
      Unless I’m totally missing what you’re saying here 🙏

    • @AlexanderCerutti
      @AlexanderCerutti ปีที่แล้ว +1

      ​@@andrew-burgess I also wrote this comment like three times because I was trying to link the codesandbox I created as an example (starting from the code you shared), but probably TH-cam bots were keeping deleting it ahah.
      Yes, we're kinda talking about normal promises. The difference here is that you are able to determine whether your code is synchronous or asynchronous or will run on microtask queue. So you can have a way more dynamic way to handle your operations. The cost is that thenables are completely "raw", so you have to implement your queue system for callbacks, determine what a 'then' should be able to return and so on.
      About the "exposing internals", my point of view is that if you access to something that is passed to you from an internal / native implementation (just like resolve and reject) and you are bringing it outside (outer scope), you are exposing it. I feel some code smell in that case (so, by using the deferred pattern).
      On the other side, if you move everything inside a Promise, it feels to be better because you are not exposing anything and you are doing everything in that scope. Of couse this is trade-off with indentation (one indentation level more than with deferred). Also, its worth noticing that you are adopting another different pattern here, which involves (let's call like this) an "unsubscription function" as return value instead of the promise. Otherwise, using just the promise you wouldn't be able to stop the recording, and this is not okay.
      That's why I think that thenables here are the best way.
      I'll share the url of the code I refactored with thenables in the next comment. Maybe in a way that it is not a URL to bots.

    • @AlexanderCerutti
      @AlexanderCerutti ปีที่แล้ว

      On the same project I've also added an example with the function instead of the class. Let me know!

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว

      @@AlexanderCerutti I think youtube pulled your comment with the link again, but I was able to get the URL from a notification, so taking a look now! Thanks for all this detail!

  • @mazingguitar
    @mazingguitar ปีที่แล้ว

    Sorry, but RxJS is love and life. Would lean towards them every day of the week.

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว

      Yeah, observables/async iterations are 🔥

  • @__edward
    @__edward ปีที่แล้ว

    or you could wrap the event listeners in a promise and resolve that directly
    return () => {
    return new Promise((resolve, reject) => {
    mediaRecorder.addEventListener("stop", () => {
    const blob = ...
    resolve(blob);
    });
    mediaRecorder.stop();
    });
    }
    Usage:
    const stopRecording = recordStreamAsBlob(stream);
    const blob = await stopRecording();

  • @goncalomarques7502
    @goncalomarques7502 ปีที่แล้ว

    Would blob be undefined in the example without Deferred because event handlers are called asynchronously or something like that being put in the event loop queue and stuff? So blob will never be assigned before the function returns? Is it because of that or am I missing something?

  • @vim55k
    @vim55k ปีที่แล้ว

    Cool

  • @paulo.8899
    @paulo.8899 ปีที่แล้ว +3

    Hey, Andrew do you ever pause to consider that half your audience gives up midway on your videos because you're running thru your content too quickly? TH-cam isn't running out of space anytime soon. An extra 3+ minutes isn't going to hurt. Not trying to be jackass.

    • @andrew-burgess
      @andrew-burgess  ปีที่แล้ว +1

      Good feedback, thanks my guy. 💪

    • @PRonYouTube
      @PRonYouTube ปีที่แล้ว +5

      I disagree! Thought this was the perfect length, any longer I probably wouldn't have watched.

    • @paulo.8899
      @paulo.8899 ปีที่แล้ว

      @@andrew-burgess sure thing, my guy 💪💪

    • @gnack420
      @gnack420 ปีที่แล้ว

      It's fine, if you want it slower there's an option for that.

    • @MattChinander
      @MattChinander ปีที่แล้ว

      The length is fine but I think the point of using this pattern was missing and/or wasn't well explained.