Rethinking Asynchronous JavaScript

Exercise 3 Questions Part 1

Kyle Simpson

Kyle Simpson

You Don't Know JS
Rethinking Asynchronous JavaScript

Check out a free preview of the full Rethinking Asynchronous JavaScript course

The "Exercise 3 Questions Part 1" Lesson is part of the full, Rethinking Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Kyle spends some time answer audience questions about exercise 3.


Transcript from the "Exercise 3 Questions Part 1" Lesson

>> [MUSIC]

>> Kyle: Questions about exercise three. Yes?
>> Speaker 2: Well, I have p1 then functions, and then I have that under the options. I [INAUDIBLE].
>> Kyle: So, you're saying put the dot then here?
>> Speaker 2: I put it under [INAUDIBLE].
>> Kyle: Is that what you're saying?
>> Speaker 2: [INAUDIBLE] Like that? [INAUDIBLE] Then functions, no, this happened then, functions output.

>> Kyle: You're saying you took this one out.
>> Speaker 2: Yes.
>> Kyle: You did output text.
>> Speaker 2: Yes, and then return p2.
>> Kyle: And then return p2 is that correct?
>> Speaker 2: Yeah.
>> Kyle: Valid solution, but that's not as promise chain oriented. I would prefer to keep the output and the chaining in separate places.

Separate steps to reason about. This will functionally work, but this isn't the style I would personally prefer. I prefer a style where the steps are more explicitly separate. You wanna think about, this is just general programming practice. Functions should be as single purpose as possible. So, don't make a function that does two entirely separate things, outputting the response from a previous one, and sequencing in yet another thing.

Those two tasks are separate concerns, and they belong, in my opinion, a separate steps in the chain.
>> Speaker 3: So, you need to resolve the comma splice? And then you have two then statements for p1 there to result twice?
>> Kyle: No. The question was, if I said somewhere else in my program, if I had another p1., then logValue, for example.

So now I have two p1.then's. I register two then handlers on the same promise. That's not the same thing as off the chain, cuz this is a different promise. But here, I have two then's handlers registered in the same promise. Does resolve need to get called twice? Absolutely not.

You call resolve once, and the promise becomes resolved to that value immediately and forever immutable, no matter whether you observe beforehand or after hand, and no matter how many times you observe it. You're still going to get that same value. It's exactly like with our thunks. Every time we call the thunk, we're gonna get that same 25 value out, for example.

So here, only one resolve, and both log value and output would get called with that value, as well as any future times that we called p1.then. Yes?
>> Speaker 4: I'm a little confused about what the output returns so that you can chain it.
>> Kyle: Every time the then method, this is getting a little bit into the implementation details.

Every single time that then method is called, it actually does return its own promise. So, when I chain right here on line 37, I am chaining off a new promise that was created and returned by that method. That new promise is set to, by default, be resolved immediately.

Unless the previous step returns another promise, in which case it sort of hijacks. That's that complicated under the cover stuff that I said, seems simple and it's actually pretty complex. That part's handled for you. So, this is automatically chaining off of a new promise.
>> Speaker 4: So, what would the input to that function be?

Well, it would be-
>> Kyle: Because we don't return anything from output. If I returned something like, hello there, that value that I'm returning from that promise would automatically get piped in and come in here is an argument. But since I'm not returning anything from output, nothing goes.
>> Speaker 4: So it's undefined?

>> Kyle: Well, it's the same, all JavaScript functions that don't have a return are the same thing as return undefined. Yeah?
>> Speaker 5: They're asking, is the function or passing to .then the value of result?
>> Kyle: No. I don't understand the question, but I know that that it's the answer is no.

>> Speaker 5: So, I think he is asking output, what is the value of that?
>> Kyle: I need to know a line number that somebody is asking about.
>> Speaker 5: I'm 36.
>> Kyle: Line 36. What is the value of what? The value of the output function, or the value of the .then function?

>> Speaker 5: Where is the resolve defined?
>> Kyle: Resolve is defined here. It's passed into our promise constructor by the promise mechanism. All we have to do is call it.
>> Speaker 6: The previous example where you had a p1.then with log on the result.
>> Kyle: Uh-huh.
>> Speaker 6: What's the order? Would it execute output first or log first?

>> Kyle: The order will be if you have two different then's on the same promise, which is what we have here. Keep in mind line 39 is not a .then on p1 anymore. It's on a different promise entirely. But line 38 and line 35 are then's on the same promise.

In those cases, they go in first, registered first, executed order. You really should not pay any attention to that sort of detail, though.
>> Speaker 6: [LAUGH]
>> Kyle: You really, really, really absolutely should not. Reason about what order something was registered on the promise in, not that it's not reliable, it is, that's guaranteed by the spec.

This is terrible programming practice. That's way back to those pre functional programming concepts that we're talking about where you can't understand the state of your system, cuz you don't see it all at once. So, promises invite you to embrace the idea that you are dealing with independent things that you shouldn't.

You should not build dependency between the resolution of promise handlers if you can avoid it.
>> Speaker 6: Right there. He's kind of following up on his question, but he's, I don't see where we pass the resolve value into the promise.
>> Speaker 5: That gives us-
>> Kyle: The resolve value, I think maybe I'm just, it's maybe being just, it's hard to understand the way the questions are being asked.

I think what's actually being asked is you not seeing the fact that this on line 24, this resolve function is that CB up here in our fake AJAX. And down here is where we're calling the result function and passing text in.
>> Speaker 7: And that is output. Output is a function?

>> Kyle: No.
>> Speaker 7: No?
>> Kyle: No, no, no, no, no. Resolve is the thing that's getting passed into fake Ajax.
>> Kyle: Not output.
>> Speaker 4: But we're passing the function.
>> Speaker 2: Function with the response and resolve with response. Does that make more sense? On line 24?
>> Kyle: Does that make it easier to understand?

>> Speaker 4: And result is not output.
>> Kyle: No, result comes from the promise constructor.
>> Kyle: This is built into JavaScript.
>> Speaker 4: Yep.
>> Kyle: It produces a function that we happen to call resolve. We could call it Fubar if we wanted.
>> Speaker 4: Yep.
>> Kyle: That's coming from JavaScript, not from us.

>> Speaker 4: Okay.
>> Kyle: Output is being passed to the then function, which is happening at an entirely different part of the-
>> Speaker 5: I think they might be getting lost on the idea of where promise comes from. And-
>> Kyle: It's built into JavaScript.
>> Speaker 5: Right, I think that's where he's confused here.

>> Kyle: I don't know what else to say other than to say it's built into JavaScript, that's where it comes from.
>> Speaker 5: ES 6.
>> Kyle: It's built in the ES 6. That's correct.
>> Kyle: If one of the promises misbehaves and fails, does it fail the whole flow? Yes, if p1 here were to somehow reject, then every one of these then handlers that does not listen to the reject.

They automatically have an implied reject handler that just simply propagates it to the next step. So, that rejection would propagate all the way down the chain. Since we never listen for the rejection, it would sort of just sit there waiting to be observed. It's not really been swallowed, it's there.

But we are not passing in a rejection handler to listen for it.
>> Speaker 7: Is that a new rejection as it propagates through the then's?
>> Kyle: Yes.
>> Speaker 7: So each one will get a new one.
>> Kyle: Yes, the default rejection handler, because we're not passing in any rejection handlers.

The default rejection handler receives the rejection from the previous step and rejects.
>> Speaker 7: With the same parameter.
>> Kyle: Same value.
>> Speaker 7: Same value. Okay.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now