Rethinking Asynchronous JavaScript

Synchronous and Asynchronous Thunks

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 "Synchronous and Asynchronous Thunks" Lesson is part of the full, Rethinking Asynchronous JavaScript course featured in this preview video. Here's what you'd learn in this lesson:

Thunks are functions that already have everything they need to return a value. They do not require any parameters. Kyle explains how thunks typically manifest themselves as a function wrapper around some state or token value. Hey also demonstrates the difference between synchronous and asynchronous thunks.


Transcript from the "Synchronous and Asynchronous Thunks" Lesson

>> [MUSIC]

>> Kyle Simpson: All right, let's talk about a pattern on top of callbacks. This has actually been around for a really, really long time. It way predates JavaScript, this terminology didn't even really exist in JavaScript until people started trying to adopt this notion in JavaScript, and the word is Thunk.

I have no idea where they came up with this word, I don't know what they were smoking, I wish I had some of it. It's a weird word, I don't even know what its origin is, but I can describe to you what I think it is and it's actually kind of deceptively simple.

What a Thunk is from a synchronous perspective, a Thunk is a function that has everything already that it needs to do to give you some value back. You do not need to pass any arguments in, you simply call it and it will give you a value back. Does that sound familiar?

You remember how we were talking about that before in a different workshop? A Thunk is just a function with some closure state keeping track of some value, or values, and it gives you those things back whenever you call the function.
>> Kyle Simpson: Here's a synchronous thunk. I've got an add function, which expects an x and a y, and I make a thunk that calls the add function and already has the 10 and the 15 in it.

It's hard coded in this case. Every time I call like I do online, so that's line 9 to call the add function, but every time I call line 9, if I call func over and over and over again, I'm gonna get the same value out every single time.

So, now here's the important part. Func itself value, which is a function, it has become a container around that particular collection of state. And that is now a container that I can pass around anywhere in my program, as a container wrapped around that state. And any time I want to extract it, I simply have to call that function and I get the value out.

I don't have to pass the value or the state itself. I passed the wrapper around that state all around my program. So it becomes like a token that represents this value and it's easy to get it out. All I have to do is execute it to get the value out.

>> Kyle Simpson: You may not realize it yet, but that is the fundamental conceptual underpinning for what a promise is, a wrapper around a value Here are the wrapper as a function in promises it's a much more sophisticated thing. Was actually quite powerful to think about when we extend phones from the synchronous nature into an asynchronous nature.

This is a synchronous thunk and that's the most common definition for them to find is that it's a synchronous thing. What is an asynchronous thunk? Well, there's no right or wrong definition here. But the most natural way that we could define an asynchronous thunk is that it is a function that doesn't need any arguments passed to it to do its job, except you need to pass it a callback so that you can get the value out.

>> Kyle Simpson: So that's what we're gonna call an asynchronous thunk. So let's extend our synchronous thunk to an asynchronous thunk. I have an add async function. It fakes some asynchronicity with a set time out. Takes the callback that you've passed in on line 1. On line 3, it calls it with the addition.

So we make our thunk on line 7 with addAsync, and we hard code (10, 15, cb). And on line 11, we have that value that thunk value that we can pass around our function. And every time we call thunk and pass in a callback, we know we're going to get our value out.

But here's what's incredibly powerful about this pattern. From the outside world we do not know nor do we have to care whether that value is available immediately or whether it's gonna take a while to get us that value. What difference is a make to us we pass on a callback we know you'll call the callback when you have a value ready for us.

So the first time we call func and we pass in a callback, it might have to do some significant work to calculate the answer to your question. It might make some ajax call, and do some other kind of crazy calculations, and it might take a while. And then it may decide to memorize the answer to that question, so the next time you call it, it just gives you the value back right away.

But from the outside world does it matter to us whatsoever how that works. What's happening here is that by wrapping this function around the state and allowing it to be asynchronous in nature we have essentially normalized time out of the equation we have factored time out of the equation.

We have produced a wrapper around the value that has become time independent. It doesn't matter if the value is there now or if it's gonna come later we still use it in the exactly the same way. Hear this if you don't hear anything else that I've said today.

Time is the most complex Factor of state in your program. Managing time is the most complex state in your program. That's why this is huge to be able to come up with a very simple, there's no libraries involved, this is straight up core JavaScript. Just a different way of looking at and using the mechanisms that have been available to us for all 20 years.

We've taken this notion, this fundamentally difficult thing to reason about called time and we've eliminated it as a confusing factor. As a complicating factor. I have this thunk, it represents a value, I pass it around whenever I want the value, I give it a call back and I get the value out then that's all I have to do.

>> Kyle Simpson: I can tell from your faces that you're not realizing how groundbreaking that notion is. Okay but that is one of the most important I couldn't believe when I recognized what that meant I could not believe how far. I had gotten in JavaScript without that realisation. It changed everything for me.

And in fact it's what helped me understand promises. I didn't fully understand the conceptual basis for promises until I understood what thunks were doing. Because we'll find out that a promise is a time independent wrapper around a value. Just has a fancier API. So as I said earlier, I like to say that thunks are promises without the fancy API.

>> Kyle Simpson: Okay? Now There are some twists, there are some wrinkles that we can throw into the situation. If I wanted to make a Thunk like give myself a generalized utility for making Thunks. I can do all that old crappy array stuff and. Pushing the arguments on and calling apply.

I could do it that way. And I could use it this way as we see on line seven. So now I'm not manually making one but I can make any thunk that I want by presetting the callback as the first argument, and anything else that I pass, it's going to get passed along to it always And that's how I could produce my thunk.

So I could make myself a utility for making these, which would be not fundamentally terribly different from a promise constructor. makeThunk would be kinda like a promise constructor. It's a constructor for thunks. Yes.
>> Speaker 2: Could you go through the, so when we talked about the Problems of callback this inversion of control not to early, not too late, not too many times.

>> Kyle Simpson: Yup.
>> Speaker 2: In just to stumble bit on that with how the promise is.
>> Kyle Simpson: We're not gonna we're actually not gonna have any solution to inversion of control of that.
>> Speaker 2: Yeah OK.
>> Kyle Simpson: Promises are going to solve the inversion of control. We're not quite there.
>> Speaker 2: Yeah, okay.

That makes me more Yeah.
>> Kyle Simpson: We haven't solved conversion control yet. We're laying the conceptual under pinning for promises and that's why we're looking at that.
>> Speaker 2: Yeah, I just wanted to cause that realization happened earlier we're going to. Now getting at better understanding what promises and just wasn't sure how much the fancy the is you know solving our problems or how much is it.

>> Kyle Simpson: Yeah, got it. The thunks really aren't addressing inversion of control The nature of how promises are designed are designed to solve that. So we'll get there okay. Your question about going over Slide 39 again. This is a synchronous thunk as you can see I have an add function that receives an X and a Y.

And I make another function called thunk Which doesn't need any arguments at all. Thunk can simply be called because it is hard coded to know to call the add function on line six. And it's hard coded to know to pass in the values 10 and 15, also on line 6.

So everywhere we do something like we do on line nine we're gonna get the exact same value. That's a synchronous thunk Slide 40. The asynchronous version. Exactly the same concept except when we need to pass in a call back to our thunk. So line 11, I can't just call thunk and get the value as a return value.

I have to call thunk and give it a call back which will receive that value as I do on line. You're going to get a chance to practice with thunks, I promise. All right. So here's a rewriting of that silly running example, calculating the meaning of life By using thunks.

Now you know something slightly different from what I did before. On lines one and two, I precreates some thunks. I say that get ten needs to when it's invoked call get data with the value ten. So line one is not actually made that Ajax request yet. That's important understand.

All we've done is create a wrapper that when called will do that Ajax request. Okay. So I pre set up the get 10 in the get 30 thunks and I can start using them so on line 4 I use it. Call get 10 give it a call back.

I know a thousand milliseconds from now number one will have the value 10 then I use the get 30 thunk on line 6 and there is the line 9 I create another thunk. Why couldn't I create that thunk, the one from line nine, why couldn't I pre create that up on line three?

Because it's temporarily dependent upon the responses from the first two thunks. Does everybody see that. So that's why I had to defer the creation of that particular thunk. Bottom line 13 I can simply call get answer which is my thunk and I will retrieve that now get an answer happens to be a container around that value and I can pass get an answer all over my program and anybody that needs the meaning of life can simply call that give it a callback and get the answer back.

There's something really important to note here as I said it's important to note that this particular expression of a thunk, is what I guess I would call a lazy thunk. If I was really trying to come up with some terminology for it's a lazy thunk in that it doesn't do the work.

Until you call it the first time. You could make an active thunk which did the work and just held on to its response. So it did the work right away and held on to the response. That is another way of doing a thunk. And I'm giving you a gigantic hint for your upcoming exercise.

>> Speaker 3: It's like deferring a promise or something.
>> Kyle Simpson: It's a lot like a promise. That's what I'm saying these are the conceptual underpinnings. So our current expression of thunks is very lazy. It is possible to do thunks in a different way. Which they are active. That means the first time they're called they do the first time they're set up they do the work and they don't give you the answer until you pass in the callback.

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