- [Instructor] 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 gonna go into our exercise files
under chapter one, under chapter one one
and I'm gonna go ahead and grab the start folder
and I'm gonna drag that start folder
over to my code editor so I'm gonna 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.
The result, the hidden string
is returned from the function
using the return keyword.
Returning the result of a function
like this is referred to as direct style.
Whenever we return a value from a JavaScript function
we are working with code synchronously
using direct style.
So I'll go ahead and just add one more line
console
dot log
and so we know when our program has ended
and again I'll go ahead and run this over here
in the start folder by typing node dot
and we can see that we see the Xs before
we see the end being logged to the console.
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 gonna do
is take in another function as an argument,
so the hide string function is now gonna 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 gonna go ahead and type done
and I'm gonna 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 gonna get rid of setting hidden equal to
what was returned from the function
and instead we're gonna 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 gonna 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 gonna 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 sorta 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.
Our code no longer executes the order
that it appears on the page,
it executes when it is ready.
As JavaScript developers, it's up to us
to keep track of when our code is executing.
I'm gonna go ahead and replace the code
that we see here, the index,
with another example,
a delay function.
So we will add a delay
that we can pass a number in seconds
and a callback so within the delay function
what we'll do is we'll call a set time out
this is another way to introduce asynchronicity
into our code and we will invoke
the callback function after the number of seconds
times 1000.
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 gonna 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.