Rethinking Asynchronous JavaScript

Callback Problems: Not Reason-able

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

The second problem with callbacks is they don’t handle divergent code very well. Kyle describes this as not being reasonable or understandable. His goal is to write async code that looks synchronous and sequential. This can’t be done with callbacks alone.


Transcript from the "Callback Problems: Not Reason-able" Lesson

>> [MUSIC]

>> Kyle: The second tenant of call back L. Well, I'm gonna fundamentally declare or assert that callbacks are not reasonable. And I highlight reason to say suggest I don't mean reasonable in the sense of like likeable. I mean reasonable, they are not able to be reasoned about. Let me try to illustrate.

How many of you have ever heard before or said before to yourself, I'm a multitasker? Anybody ever say that before? It's pretty common. People talk about, I'm driving down the street, I'm talking on the phone and texting, I have my laptop in the seat next to me, and listening to the radio, and Mom is on the phone.

Doing a whole bunch of stuff on multitasking. Well that's nonsense. We're not actually multitaskers. At our highest level of cognition, which is the only part that I care about right now. I'm not a neuroscientist, so I'm not really speaking as a neuroscientist. But from what I know and from what we can observe, at our highest level of cognition, our brains are fundamentally single threaded.

At any given instant our brain is only thinking about and cognitively thinking about one exact thing. Plenty of other parts of our brain are taking care of all the other out of some of things like our heart and breathing and all that other stuff. I'm not talking about that.

I'm talking about the highest level of cognition the part where we are intentionally planning and thinking about things. And at that part we're only thinking about one thing at that exact moment. So, let's imagine this morning when you all woke up. This morning you thought to yourself, I gotta planned out my day.

So, when you woke up, you started planning a day like, well I got to get some coffee, and I'll hop in the shower. And then I'll get in the car and drive to work and then I'll head over to this workshop and you planned out your day in a very sequential step by step fashion.

Virtually all of us our brains would say that's our brains work, we think about things in a very sequential fashion. However, I'm also willing to bet that virtually none of you had your morning play out exactly the way you planned. You were up making some coffee and then your mom called, so you got interrupted by that call that wasn't part of the plan and then this other stuff happened and your car was out of gas and your plan had to change.

And thankfully you didn't have when your mom called me like, well there's the whole day shot I didn't plan for that. So, I better just go back to bed and start of tomorrow. Your brain thankfully is interesting a lot like the JavaScript engine, in that it can be interrupted event wise.

Like an event, you can have an event fire and it can choose to respond in a just. But that's not the part we care about, the part that we care about here is the part of our cognition where we planned things. And fundamentally, what I'm gonna argue is that we naturally plan things and sequential synchronous step by step fashion.

So, if that's how we plan things, that's also how we code, most naturally. Now I have a theory here. This is not a law, it's as close to as proven a law as I can probably get. I have this theory that any place where our brain diverges from the way the JavaScript engine works.

At that moment where the two diverged it is at that moment that bugs happen in our code. Wherever our brains diverged from the way the JavaScript and yours. I can't do anything about how the JavaScript engine works. It just works that way I can teach you better about it, try to train your brains better.

But I can also try to offer you patterns that allow you to program more naturally like your brain, so that there are hopefully less bugs in your program. That's basically my theory of teaching. How do I train you to write your code, so that it works more like your brain so that there's less divergence and less bugs.

So, it's more reasonable, it's more understandable. We see callback don't really offer us much accordance in that way. Because we could think about it from a pseudo task perspective like you know what I love about pseudo code? Pseudo code awesome because you just get to invent magical stuff out of thin air.

I wish I could get paid to write pseudo code all day, cuz it'd be the funnest job in the world. I get to invent stuff like on line three where I invent pause. This magical thing that I invoke called pause, which doesn't actually exist, but it doesn't matter cuz it's a pseudo code.

And then, on line what is it, on line 9 I invent this other thing that also doesn't exist called resume. I just magically pick up where line 3 left off, right? That's how I'd write this out in pseudo code. But as soon as a developer got hold of it, he'd say no no no, this, you're just making stuff up.

That's is not how it works. So, they'd begin to rearrange things, and they might rearrange the pseudo code like that. And they say well, we can do this pause and resume thing and then a pause and resume and see what we've done now? We've started to implement this is a series of nested callbacks.

Because callbacks alone that's the only way for us to express and listen here's a here's a fancy term for you. Temporal dependency. When one thing depends upon another thing finishing before this thing can go, that's a temporal dependency. And the only way with callbacks for us to express temporal dependency is nesting one inside of the other, the call to one inside of the call to the other.

Whether we do so within line function expressions or with just the function calls. The only way to handle temporal dependency in callback alone, is through nesting. Why is that such a problem? The reason it's such a problem is now your brain doesn't get to linearly progress through the code.

Your brain has to do what I call non-local jumps. Here's a metaphor for you. How many of you remember way, way back. I'm talking like mid 80s, the original Nintendo. And my favorite game of all time in the original, and into Legend of Zelda. Anybody remember have to leave the thing running forever and play it would take weeks to play through whatever.

You know what I loved about that game though there is one part you would go into a cave. And all of the sudden the screen would go completely black. Except for this tiny little circle around link where he's holding his torch up. And you can see just a small little portion of the map at any given moment.

Now you can move link all over the cave you could see the entire map but only this little circle at a time you could not see the entire thing all at once. That's what modern JavaScript programming is today. Modern asynchronous JavaScript programming. Now this is not a knock on any individual person listening to this to suggest that you are just fundamentally bad programmers.

We are all limited in this fashion, that the complexity of asynchronous flow control that happens in our programs? There is no developer on your team that understands all of those flow paths. It's just it's beyond our capacity to understand. You might get step one, then step two, then step three.

But as soon as you get like step one, two and three at the same time and when these two finish fire it off here and there, you're completely lost. You can understand only just this small little portion you get that and then you move over here and you understand this part.

And then you move over here and you understand this part. And heaven forbid when those parts are where the callbacks are jumping around between the files of your program. And you're fundamentally not able to plan out your program the way your brain works. Cuz callbacks alone don't have a way of expressing things, in a sequential synchronous looking fashion.

It seems like it's almost impossible to do it. Doesn't it? Doesn't that seem like almost a unicorn like there is no way to do asynchronous coding in a synchronous fashion. That's like having false be true at the same time, that seems impossible. When going all the trouble to talk about this to suggest actually it is quite possible.

But that's why we need a better pattern. Because what we need to do to solve callback hell is to be able to express our code in a synchronous sequential fashion the way our brains think. So, when we write code like that first half of my program then the second half of my program.

And we think to ourselves that it's like blocking 1000 milliseconds. Which doesn't really exist in the JavaScript engines is actually I'm gonna do a whole bunch other stuff during that. But we need to do is restore the ability to express things in a synchronous sequential looking fashion.
>> Kyle: That's the other part of callback hell that we need to fix to make our synchronous code fundamentally more reasonable.

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