The think about node.js is it’s asynchronous, there’s only one thread and how effective our applications are at sharing the single thread across multiple processes is up to us. In this next section, we will review essential techniques and patterns for working with asynchronous code, the first and most basic technique that is core to node.js is the callback pattern. A callback is a block of instructions wrapped in a function so that it can be invoked when an asynchronous operation has completed. Lets go ahead and look at some code. So I’m goanna go into our exercise files under chapter one, under chapter one and I’m goanna go ahead and grab the start folder and I’m goanna drag that start folder over to my code editor so I’m goanna drag it over to Atom and we will open that folder in Atom.
Also go back to the files and drag the start folder over my terminal so that we can open that location in the terminal as well. Now I want the terminal in my code editor to be side by side, I can do so with the mac by holding the green button and then releasing my terminal window on the right side of the screen and then selecting my code editor for the left side of the screen. I’ll close out some of these extra files here and we’re looking at our first example, the index.js that’s within that start folder. I can actually collapse, hide and show the files in the project menu in Atom by holding command backslash, so command backslash will toggle my file menu.
So before we can discuss callbacks, let’s take a look at some synchronous code. So here we have a little application that has a hide string function and what it will do is it will replace the string that we sent to the function with Xs. So I can come out here to my terminal I’ll clear the current screen and then by typing node dot I’m telling node.js to run the default index dot js file within the start folder and I can see my result hello world replaced with Xs. This code is synchronous, the hide string function is executed immediately on the current thread.
Now direct style is not the only way that we can return values from functions. Let’s go ahead and modify the hide string function to pass its value back using something called continuation passing style or CPS. Now to do so, we’re not going to use the return keyword, what we’re goanna do is take in another function as an argument, so the hide string function is now goanna take in the string and a function that we can use to pass the value of the hidden string back to the consumer. So I’m goanna go ahead and type done and I’m goanna go ahead and surround the results of the string that replaced with the done method so we’re actually passing the hidden string back via a function.
Now using continuation passing style looks a little bit different, we’re goanna get rid of setting hidden equal to what was returned from the function and instead we’re goanna capture the hidden variable via the arguments of the function that we pass as the second argument to hide string. So I’ll go ahead and move this console log here within this function too. There we go and what you’re goanna notice is when we come over to the terminal and then we go ahead and save this. When we come over to the terminal, we’re goanna run it and our results are the same so we see our hidden string, hello world, Xed out and we also see end showing up second.
You may be saying to yourself, that hide string function looks like its using a callback. This is sort of true but if we wanted to get really technical about definitions, a callback needs to be asynchronous. This code is still operating synchronously. So we’re using a function to pass the data back but we’re still operating synchronously, meaning that the entire thread has executed in order when we call hide string, the value’s passed back to hidden and that is executed immediately. So to have a callback, we actually need to introduce some asynchronicity into our hide string code.
Now I can do this by invoking a process dot next tick. So process dot next tick tells node.js to invoke the function that we send to next tick on the next loop. So this is going to be on the next node.js loop and it won’t happen synchronously. Let’s go ahead and go over here to the terminal window and run our code. And now you can see the word end shows up before the Xs and that’s because all of our code is executed and then we’re actually passing the results back in the next tick or the next loop.
So our hidden string is being logged in the next tick or the next loop after our end string has been logged. So this is a callback, specifically the done function is the callback. Now that the hide string has a done function to handle the results, it can wait to execute that done function whenever it’s ready. Because we wait until the next tick to pass the results back to the done function, that’s the key that makes it a callback. So now we have to keep track to when specific lines of code execute. We did not want the log hidden until we get a result from the hide string method.
So now, we can actually use this delay method to create some asynchronicity within our code. So console dot log starting delays and then we’ll go ahead and use the delay function and we will delay for two seconds and then this callback function will be invoked after our two second delay. And if I save this and clear the terminal and run the same file again so we see starting delays and then after two seconds we see two seconds.
So you can see how callbacks can be used to handle asynchronous code. The callback is not invoked until it’s ready, until we wait two seconds. Now we can sequentially execute delays using callbacks. All we have to do is further ness delay calls within the callback so I’ll go ahead and delay for another second and I’ll go ahead and do a log here three seconds and we’ll go ahead and be good and put some semicolons in this code even though I typically do not use them.
We’ll go ahead and add another delay as well we’ll delay for another second and console dot log four seconds. Alright there we go so I’m goanna go ahead and save my file and let’s go ahead and come to the terminal and run it so we can see we’re starting delays we wait two seconds, three seconds, four seconds. So using callbacks we can supply code to execute when something happens. The above code is an example of sequential execution with callbacks. When the first delay has completed, we log a message and execute the next delay.
By repeating this pattern, we’re able to execute the console logs sequentially when it is time for each log. However we create some pretty nasty looking code as well as a specific anti pattern called callback hell or pyramid of doom. In the next lessons we will examine some techniques for dealing with callback hell.