In the previous exercise,
we learned about two new aspects of JavaScript,
their support for first class functions and closures.
We also saw how Node handles the asynchronous programming aspect and how Node
supports asynchronous execution of code with
the use of callbacks and also error handling.
Let's look at an example of how we make use of this
within our Node application in this exercise.
Continuing with where we left off in the previous exercise,
now I'm going to go and modify the rectangle Node module,
so that it can take the help of callbacks.
So I'm going to remove these exports here,
and instead, they're going to modify this function.
I'm going to be making use of these two functions a little bit later,
so that's why I'm saving them at the bottom.
So let me keep them aside.
And then I will modify this rectangle module as follows.
So we'll say module.exports.
So we're are using the standard way the module is handled.
And this is going to export this function which takes these three parameters,
x and y and callback.
The callback is a function that is going to be supplied in when this module is called.
So this is the use of the first class functions that we have talked about earlier.
So inside this callback,
so you can see that you're getting two parameters, x and y.
In this case, for the rectangle,
the x and y correspond to the length and breadth of
the rectangle that is being passed in as the two values.
So inside here, we're going to check to see
if x is less than or equal to zero or y is less than or equal to zero.
We have written code like this here.
So I'm just going to copy this code from here
and then bring it over to here and then we'll edit.
So in this case, this is if x is less
than or equal to zero or y is less than or equal to zero.
In this case, what do we do?
In this case, we notice that
the dimensions of the rectangle are less than or equal to zero.
So we have to handle it differently,
and we'll do the else part of it.
The else part where we handle the situation where the rectangle is a valid rectangle.
So in this case,
what we will do is to then use a setTimeout.
So here, I am simulating the fact that whatever
is being done in this rectangle is going to take some time.
So this is the asynchronous processing.
Now, since I don't have a lot of work to do in the background,
so I'm going to simulate that by simply using
the setTimeout function of JavaScript and then
delay before the callback function is called.
So the way I arrange this is as follows.
So inside the setTimeout,
I'm going to call this function there
and arrange a delay of
2,000 milliseconds or two seconds after which this function is going to be called.
So if you recall,
the setTimeout that is supported in JavaScript,
it takes as the first parameter a function and
the second parameter would be the time period for which this is going to be delayed.
So let me indent this in.
Now, I need to fill in this function here.
So I have started out with the arrow function here
which takes no parameters and then when there is called,
I'm going to issue a call to the callback.
This callback is a callback function that is
going to be passed in as the third parameter here.
This callback function, as you noticed, takes two parameters.
The first one is the error and the second one is the return value.
So in this case, since we have an error,
because x is less than or equal to zero and y is less than or equal to zero,
so the first value I'm going to pass in as new error,
and this error is exactly this string that I was using in the console.log then,
and that is what I will pass in as the error here.
Let me now delete that console.log,
I no longer need it.
So for the callback,
I'm going to generate a new error object and then pass this
in as the return value for the callback function, the first parameter.
So I'll say rectangle dimensions should be greater than zero.
So we'll say l,
this is the x and the y value that we got as the input values there.
So that is the callback.
And the second part of this callback,
I'm going to pass in as null because this is going to return an error.
So when you return an error as the first parameter,
the second parameter will be ignored when that callback was just received by
the node module from where we are calling this particular function there.
So, with this arrangement,
so less than zero,
so let me give some space here so that it's properly indented here.
So, the way I am arranging this
here is that if x is less than zero and y is less than zero,
I'm going to callback the callback function that has been passed in,
but the first parameter will pass in in
error because here we notice that there is an error,
and the second parameter will be null.
If this is not the case,
then I'm going to call the same callback,
but with the first parameter.
So let me copy that code in here.
I'm still going to use the setTimeout here.
But that first part is not going to be an error,
instead, the first part,
in this case, there is no error.
So I'm just going to pass back that value as null.
So that means that the error is set to null.
So this is a valid rectangle.
So we can compute the values for the rectangle.
But instead, I'm going to simply pass in
a JavaScript object containing the two functions
as the two values inside this JavaScript object.
So, here I am going to take this two,
the perimeter and the area,
and then these two will be passed in as the two values here,
perimeter and the area.
And these two, since they happen to be a JavaScript object,
so perimeter and area will be
the two properties that I will pass in inside those JavaScript object,
and that is it.
So here, in the second case,
the error is set to null because there is no error,
but the second part,
notice that I am passing in a JavaScript object containing two properties,
perimeter and area, which are two functions here.
So the two functions are the perimeter function and area function.
So this JavaScript object will be passed back as
the return value for the callback here, the second value.
And again, I am going to delay this by
a two second interval before the value will be passed back by this function.
The reason why I'm using the setTimeout is to simulate
a delay before the callback comes in from the other side.
So this sort of represents situations where, for example,
you issue a database call to the database,
and the database needs to be read before the value is passed back to you.
So that is going to take a certain amount of time.
So I'm basically simulating this at this moment by using the setTimeout function here.
Later on, you will see that when we integrate the MongoDB with
our Express in the later exercises,
that delay would have to be simulated,
it'll be automatically caused because of the fact that you need to do
database operations behind the scenes before the data is obtained.
So here, having completed this rectangle modules update,
so here you see that the rectangle module takes in
three parameters as it's a input call here,
x, y and callback.
And so, the callback is the callback function that is being supplied here.
And this callback function will be called inside here,
and when the callback function is called,
either you pass back an error or you pass back
a function that allows you to compute the perimeter and the area of the rectangle.
Now, this pattern of calling in and passing in a callback function
from one Node module and then the second Node module which when it completes,
will pass back the result using the callback function is
exactly the pattern that you will see often repeated in Node applications.
So that's the reason why I'm illustrating it.
Of course, this is a contrived example that I am illustrating here but it shows
all the standard patterns that you will use with node
and callback functions and also the error handling.
Now, we have updated the rectangle module here.
Let's go and fix that index.js file so that it can pass in the callback function and
then handle the return value that is sent back from the rectangle module.
Switching back to index.js,
now we are going to update the index.js file as follows.
I'm going to remove this from the index.js file instead.
Here, what we will end up doing is call
this rectangle module and
then pass in the l and the b as the two parameters.
And the third parameter that I'm going to pass in is that callback function.
So the callback function has two parameters, err and rectangle.
And this callback function is implemented as follows here.
So here, you see that I'm calling
this rectangle node module and I'm
passing in the length and the breadth of the first two parameters.
And the third parameter is, of course,
a callback function which I'm implementing here.
So, this is an arrow function that I'm implementing here.
So inside this callback function,
how do I handle the return value?
So here I'll say if (err),
so if the error value is returned to you,
then I will simply do console.log and I'll say
"ERROR" and then the second value is err.message.
Recall that in the rectangle,
we had created this new error object
and then passed in this string inside this error object.
This string will be attached to
the error object to the message property of the error object here.
So, in the index.js file,
so I'm retrieving the message property of the error object
and then printing it out onto my console here.
So if an error occurs,
I'm going to print out the error message using this.
And so, this is how I would handle error that was returned by a callback function.
Otherwise, of course in this case,
the rectangle module has returned the rectangle function,
the object that contains the perimeter and the area functions,
so I can go ahead and print out that value.
So here, I'll say the area of the rectangle
of dimensions l equal to,
so I will say,
and b equal to.
The reason why I am identifying it
explicitly will become very clear when we run this example.
I'll say is rectangle.area.
Now, notice that for this area,
I am not sending in any parameters here because goes to values,
the length and the breath have been passed in already here in the l and b,
and those would be already available to this
and here because of the closure that JavaScript supports.
Because these x and y have come in as the parameters,
so those will be accessible right there in this callback function.
So those x_y will be automatically available for us here.
So, as a matter of fact,
I don't need to supply this x and y parameters here at all because
those x and y will be retrieved from this x and y right there.
So I don't even need to pass those two values in here.
So that's why, right there,
I can call rectangle.area.
And this area computation will automatically get the l and b that have been passed in
by the rectangle call to direct node module earlier.
So this is the closure of JavaScript operating here.
So, that is the first one.
I am printing out the area of the rectangle.
The same thing, let me also print out the perimeters.
So to print out the perimeters,
so I'll say console.log.
The perimeter of the rectangle will be rectangle perimeter.
Now, I must tell you that this kind of approach for implementing takes a little bit
of effort to understand and internalize the asynchronous function ability.
Takes some time for you to completely understand how it really works.
Now to illustrate the fact that
this function call will result in a call to the Node module
but this part will be executed only after
a two-second delay because of the fact that we are using the set time mark.
Now, as we studied in asynchronous operation,
because we have moved off the processing to the back,
let me also introduce one more console.log here to make a point.
So we'll say this statement is
after the call to rect.
The reason why I am illustrating this point is that when you issue this call,
this code will not be executed until after a two-second delay.
So, in the meantime,
your function, main function here,
will continue on and then execute the next line of code that you see here.
So this is the continuation that you will see here.
So, with these changes,
let's save the changes and then look at how this application executes now.
So saving the changes.
Let's go to the terminal and execute this node application.
Now, going to the terminal, add the prompt.
Let me type npm start and you will immediately notice
that the solve and this statement were printed out earlier.
And then after this certain delay,
the area and the perimeter was printed out.
So that is a two-second delay that we introduced using the set time out.
So, you noticed that in the earlier version,
this was printed and immediately the area and the perimeter was printed right below that.
But now, notice that those values are printed a little bit later.
So in between, their function calls with the different parameters that are already gone
in and then the callbacks are called back after two second delay for each one of them.
And because of the fact that there is the closure that the JavaScript supports,
so the values that get passed in is preserved.
And so when the callback function is called,
the appropriate value is printed.
So that's why you see that the area and
the perimeter are printed correctly and these two here,
these two statements here,
correspond to this particular call to direct
with l is equal to two and b is equal to four.
And then these two,
the next to two, of course,
correspond to this particular one and the remaining ones as you see here.
So, what I wanted to illustrate is the fact that when you do asynchronous computation,
the asynchronous computation takes its own time
to return the value while your main computation
will proceed forward without waiting for the callback to be completed.
So, when you need to do a certain amount of work,
you passed in as a callback to that other module.
And when that other module completes its work,
it's going to callback and then that code will be executed.
So that is the point that I have illustrated using this example.
Again, as I said,
this takes a little bit of imagination and understanding
for you to internalize the way this works,
but you will see that with Node and also Express and when we use MongoDB,
you will see this kind of pattern repeating very often in the way we write our code.
So with this simple illustration of callbacks and error handling,
we complete this exercise.
This is a good time for you to do a get comment with that message,
node, callbacks, and error handling.