Solve Callback Hell with Composition

John Lindquist
InstructorJohn Lindquist
Share this video with your friends

Social Share Links

Send Tweet

Many APIs in JavaScript rely on callbacks, so when using APIs together, we end up in deeply nested callbacks AKA "Callback Hell". This course solves callback hell through composition by moving all of the nesting into the internals of our helper functions which can expose a clean API that becomes a list of functions in a pipe.

John Lindquist: [0:00] Callback hell is the situation that occurs when you have way too many callbacks nested inside of each other. As an example, I'll set up document addEventListener. When I click on this, this will call this callback.

[0:15] Then a setTimeout that invokes a callback after one second, and then a fetch, which can grab my GitHub user id. Then the fetch to get the data needs to grab the JSON and then invoke a callback with that, so data, and we'll just console.log the data. If I click on the document, after one second, you'll see the data up here.

[0:44] Right now, we have a callback inside of a callback, inside of a callback, which is required because this click starts a timeout, which starts the fetch. Then inside of this callback, this could continue on based on your requirements, logic, and behaviors in an infinite number of ways.

[1:04] We can solve this with composition by thinking about how we can break this into functions. I'm going to extract fetch and put it into a function called getURL() and just paste it in there. I'll extract setTimeout. I'll put this into a function called timeout() and paste that in there. My click, I'll call this function click() and just paste that inside of there.

[1:28] Each of these behaviors are inside of individual functions. We just have to figure out how to wire them up.

[1:34] The relationship of nesting is essentially you invoke an outer function, which takes a callback. Then inside of that, it calls an inner function, which takes a callback. We can even define this behavior inside of a function called nest().

[1:52] This will take our inner, or the function that's being nested, inside of an outer, which is the function that wraps around. Then finally we need a listener as the function that is the callback. I can paste this inside, where it takes this, sets up a temporary callback, and then invokes inner. We can now pass our listener into the inner function. Right now, we're ignoring the value, but we'll touch on that in the next lesson.

[2:21] To be able to wire these up, it would look something like I start with a click, and then inside of the click, I'm going to call my nest function, where we want to nest the timeout. Then around that I can call my nest function around this function, and this one calls the getURL.

[2:44] This is the implementation. It won't work yet. You'll see if I click, nothing happens, because what it's missing is this listener. The listener we're using is this one right here. This is our callback. Let's extract that and pass that in here. This means that this listener is this one here, which will go into here. First of all, this listener will get passed into click. I'll put it right here.

[3:09] Replace this event with listener, then that listener will get passed down to timeout. I'll replace this with listener. Then that listener gets passed down to getURL. We'll replace that with listener and then drop the listener in here.

[3:25] Know we have everything wired up, except that I missed a paren here. I need to put this on the other side of click. Let's save, and once I click, you'll see it's back to waiting for one second and loading our data.

[3:40] We've seen this mess of parens before. As you saw, I already messed up on where one paren goes, and this is difficult to read. We've also already solved this through composition.

[3:51] If I import, you come up here, and import from lodash/fp. I'll import our pipe, then I can say pipe and start pulling these functions out. The first thing after the click is the timeout, so we'll cut that, paste it here, comma, the next thing after the click is the getURL.

[4:16] We'll cut that and paste it there, your getURL. I can name this a function like timeoutURL(), and just use that around my click. I'll say timeoutURL. Now when I hit Save, I'll click, it waits one second, and loads the data.

[4:37] Most people getting into JavaScript are used to writing functions that do things, such as logging or adding numbers or parsing strings.

[4:45] The more advanced you get, the more you find yourself writing functions to organize other functions, to help your code be a more readable and well-named, so that once you actually write the line that implements it, it will read like once I click then timeout, getURL, and log out the data.