>> All right.
So the cliffhanger was, what is node.js as you know it today?
Anything? Yeah?
>> It was like a framework writing JavaScript
applications broadly--
>> OK, that works.
>> -- I know like common uses like--
or something you can do is like--
[ Inaudible Remark ]
>> OK good.
Yeah, so it's a framework.
It's an engine by which you can execute JavaScript code
server site.
This can mean the simplest of things
like writing a command line script not in Python or Bash
or Ruby or PHP, but just in JavaScript itself
and executing it at a blinking command prompt.
Or you can actually run it within a web server.
And in fact within node.js itself,
this framework is a whole bunch of libraries among which are
in HTTP server built-in.
So, you can actually write a server as we'll see
in just a moment, super easily by just to understanding a bit
of HTTP and TCP and ports.
And you can spawn a listening web server without Apache,
without Microsoft's IIS.
Without any other software installed,
you can just spawn this and listen to most any port
on the system that you're allowed to.
So case and points, let me go and open
up this example, server-0.js.
So notice that the top of this file, just a bunch
of uninteresting comments, and then there's a couple
of representative lines of code that we'll see recurringly.
So, var HTTP gets require "HTTP".
So built-in to node.js' infrastructure is a whole bunch
of modules which are really just libraries and everything is sort
of name space with the unique identifier
like this one is "HTTP".
So that like in a lot of languages like Java and C++
and C, only when you import or include
or in node speak require a module does its bits.
And all the memory requires get loaded
into RAM and therefore used.
So, you sort of load this libraries or modules on demand.
This means go ahead and require
for this program the HTTP library,
and refer to that library by way of a variable called HTTP.
But this left-hand symbol could have been called anything, foo,
bar, baz, it doesn't matter.
So unlike C++ and Java and C where when you require
or import a library, it just sort
of becomes globally accessible,
node.js modules are more tightly namespace.
So that own-- that functionality is only accessible at the moment
by way of this variable name.
You can't just start typing methods that exist
in it right a way which is probably good,
because then your namespace doesn't get nearly as cluttered
as in a lot of languages.
All right, so now as the common suggest, creating an HTTP server
as Jonathan [assumed spelling] was possible is literally
as simple as calling the create server method inside
of the HTTP module.
So, this is returning the reference
to some kind of web server.
It came to Apache, not necessarily as heavy weight.
This one's a little simpler.
And now, I have to just simply do a few things.
So first, let me scroll down to the bottom here
and skip the handler method for a moment.
And notice this line of code,
server.on which is essentially means server--
listen like in jQuery code,
listen for an event called request
and just take a guess what should I do
when a request event fires in the server.
Yeah?
>> Call the function handler.
So, literally execute the code that's referenced
by this variable and actually not a variable to symbol here,
what is that symbol referring to?
Well, this name of function up here
and handler apparently takes two arguments.
Why two? Well, if you just read the no documentation
for this particular module, you will be told that the handler
that will be invoked will be passed at least two arguments,
a reference to the request,
and inside of the request we literally mean HTTP request.
So, all those HTTP headers that you might recall
from the beginning of the semester or some prior class
or experience like the get line and the host line
and User-Agent line, all of that is encapsulated and more inside
of this request object.
And the response object is sorted for outbound data.
So, you have a reference to an object that's going to allow you
to send information back to the browser by calling methods
on that latter argument called Res for response.
But this could be called foo or bar, this are just conventions.
So now, what do I do?
Well, it appears that inside of this super simple web server
that I'm implementing, I'm going to do the following.
I'm going to write an HTTP header with status code 200,
200 meaning OK, all is well.
And then, I'm going to pass on apparently.
What's the data type of the second argument to right head?
>> It's an object?
>> It's an object with how many keys and values?
Just one of each, right, one key value of pair.
So, 'content type'.
And the only reason I'm quoting it here is
because the hyphen might be conflated for a minus sign
or something like that.
So, I have to quote it here, singe or double quotes.
But again common paradigm
in JavaScript code is often single quotes these days,
colon and then the value.
So, this is just the so-called mind type.
This is an HTTP header that's literally going
to be content hyphen type colon text slash plain that's going
to be sent from the server to the browser
so that the browser knows whether to run this as Raw text
or HTML or as an image or a movie
or a flash file or anything else.
Now, where do I actually want to send in the body of the page?
Well, just by reading the documentation
for the response object inside of this library.
I see that there's a right method and that takes a string,
maybe other things but minimally a string.
And the string is what's spit out to the browser.
In this case its super simple, its hello world,
but it could be opne bracket, html, close bracket,
open bracket head, close bracket and so forth,
this could be Raw html.
But we're keeping the example simple by just spitting
out the simplest of mind types which is arguably text/plain.
And then response.end just means close the connection
and send everything I have sort of buffered inside
of this object back to the browser.
I'm done. All right.
So, the last thing I'm doing down here
and this is somewhat arbitrary and meant to be cool,
is I'm telling the server finally to listen
on a certain TCP by default port.
Recall from beginning of class that services--
or you typically uniquely identify it by numbers,
AD is the web, 443 is HTTP based websites, 22 is SSH, 21 is FTP
and 1337 is just arbitrary but it's higher than 1024
which means on most systems, I can use it
without needing super user privileges.
So it's just convenient.
But 8080 is in off-- a common one, 8088, really anything big
in the thousands as common but this is just more elite.
All right, so what happens when I actually run this?
Well, I don't just visit the page in a browser.
This file is called server-0.js.
Because again, Apache is now out of the picture
for the latter half of the course.
If I want to web server, I need to write
and then run this web server.
But it turns out that JavaScript both on the client side
and the server side is an interpreted language.
So, all I need is an interpreter.
So it's-- if insist to run node and then server-0.js,
I may or may not see some output depending
on what libraries I've included, nothing seems to be happening.
But let me go to a browser and let me go
to the same IP address of my CS50 clients.
But this could just as well be my Mac
or my PC and then hit enter.
That actually looks like Apache.
That's like the directory listing we looked
at in the first half.
So, what did I do wrong?
Yeah.
[ Inaudible Remark ]
Exactly, right?
So, Apache is still listening on the default port 80.
Even though I could change that, I could turn it off all together
but it's still running.
But these guys can certainly coexist.
I simply have to put colon 1337 and then maybe
or maybe not a slash at the end to access this port
that this server is running on.
And now I see that hello, world has returned.
And I can hit reload as many times as I want,
it's still serving up a page.
Indeed if I open up Chrome's inspector, go to network
and then reload the whole page,
notice that indeed this was the request that was sent.
If I look at the Raw source,
notice my browser sends all of those things.
And then the response from the server was super simple.
There is the 200.
If it's not too low on the screen,
there is the content type.
And then node.js sort of automatically
for me added the date and all of the other stuff
that browsers typically expect.
So, let's just see a little sanity check.
Let me go back to the code in server-0.js and let me--
every time I go into the handler,
let me just say console.log.
('We had a visitor!').
I don't need to recompile or anything like that,
it's an interpreted language.
So now, let me go back to the page, reload one, two,
three times and go back to my window.
And now I see this.
Well that's strange, I see six lines.
Interesting web trivia, why did I get six request not three?
Yeah?
[ Inaudible Remark ]
Yeah. So, as you may know the little stupid icon in the top
of the browser bar that a lot
of websites used might be a Harvard crest,
it might be a company logo or anything like that.
So, browsers these days sort
of presumptuously make an additional HTTP request
to almost every website that you visit checking if there is
by default a file called favicon.ico
in the same directory as the file you requested.
And if so, it puts the icon there.
So all we're seeing is exactly that.
And in fact, let's see if we can see this rather than type
out just, 'We had a visitor'.
Let me go ahead and output.
And I only know this from looking at the documentation.
There's a property inside of the request object called URL
which happens to be the path
that was requested in the actual URL.
So, if I restart the server simply by rerunning node
on server-0.js and now do this one, two,
three and go back here.
There it is.
Slash is what I-- the human requested
in favicon.ico is what the browser is
presumptuously requesting.
But the point isn't so much favicon stuff
but how the server is operated.
Yeah?
>> Why does that have to be some request?
>> Why does that have to-- by nature of how HTTP works.
So, HTTP can only request one file at a time.
Browsers can be smart these days
and keep the TCP connection open.
If you took CS143 or generally familiar with networking,
so you can get efficiency gains
by keeping the network socket open
in making multiple HTTP requests serially over it
but they're one file per request.
So, if you visit something like--
I mean we can go to most any websites.
If you go to-- let's pull up the Chrome's inspector here.
It may get fill most of the page.
Go to the network tab and go to www.cnn.com.
And when you visit cnn.com, its homepage--
your browser rather atrociously makes-- still counting.
OK. At least 289 HTTP requests again and again.
And this is why when you visit particularly bloated websites,
they're slow to load because of all
of the assets they're loading.
So, it looks like 298.
There might be some Ajax going on at this point or some
of the assets are just low.
So, each of those is an individual request going back
and forth, back and forth.
And that's why earlier, even though we sort of talked
about it somewhat fancifully where you put the script tag,
absolutely makes a difference when you have--
it start to have a lot of traffic and a lot
of files being requested.
And each of this represents probably an image, a media file,
a JavaScript file, CSS file or the like.
So, we're already up to some 4 megabytes just
to look at today's news.
Good question.
All right.
So, what are some of the upsides though?
Right, we know how to make webpages already with PHP.
And many of you came in to the class knowing Django
and Python or rails with Ruby.
So, why do we need yet another language and infrastructure?
What is node.js particularly good at if you know?
[ Pause ]
Some thing?
No? Yeah?
>> Relaying messages.
>> So, relaying messages.
So that's true and it's true for a more technical reason
and that node.js and really JavaScript is particularly
well-suited to asynchronous code,
if whereby you create the illusion
of doing multiple things at once.
So, even though they're really happening serially,
indeed in most cases, JavaScript both client side
and server side is single threaded.
Which if you're taking 161 or even 61 means that--
of this program know,
the interpreter can literally only do one thing at once.
But this is isn't great for something like a web server
where you might have dozens or hundreds or maybe even thousands
of users all trying to access your webpage
at the very same time.
And yet, that suggest that handling them one
after the other after the other especially if some
of those request as we saw on CNN might require serving
up 300 files before you even get to the next user
who wants to see the says news.
Node.js is better suited for environments like that.
Because what happens is any slow running process
like reading a file from disk or querying a database or talking
to some other network server,
that tends to have latency, right?
If you did take 61 or 161 especially all of this sort
of peripheral services tend to be much slower
than doing anything inside of the same RAM and the same CPU
that say in this case the server is actually running.
But what's nice about node.js is that you can--
and JavaScript more generally is that you can do something
and then say, "Hmm, this is going
to take me a few milliseconds or even a few seconds.
Let me sort of fork that off," but it's not a true process.
And then when it's done doing that slow running process
like grabbing rows from a database or reading a file .html
from disk, it will get back to me rather
than me having to wait for it.
So, to make this more clear.
This is my means of making this more familiar.
All right, so this is the Shake Shack in the square.
This is sort of a common paradigm
for explaining asynchronicity.
This is actually a good example because Shake Shack
and Tasty Burger are remarkably slow for what they do.
But the point is they're really good at taking orders
and taking your money after which you wait for your food.
So, this is actually a better design than the alternative.
Because suppose you walk into a store like this and you got
to the front of the line and you placed your order and you want
to burger, as best I can tell, it takes at least five
or more minutes to actually get a burger.
So, it would be kind of a bad business model
if while you're waiting for your burger, Alice [assumed spelling]
and Bob [assumed spelling] and Charlie [assumed spelling]
and everyone else is queuing behind you
and you are literally blocking the line waiting for your food.
So obviously, at Shake Shack
and other fast food places don't do this,
they do something like this.
They give you a buzzer.
And they sort of send you on your way.
And they call you back by making this little thing vibrate
or flash to get your attention.
So, this is literally what?
Something like node.js does.
If node.js or JavaScript more generally is being used
and the programmer is smart enough
to realize, "You know what?
Whatever I need to do right here could take some number
of milliseconds or seconds.
You know what?
Let me go ahead and not call it synchronously--
" that is guy blocking everyone else in line, "--
let me go ahead and sort of step aside
and simply call myself back
when that long running operation is complete."
And call back of course is alluding in this case
to a callback function, a reference to a chuck of code
that will get executed when your burger is ready,
much like this thing have some kind of functionality built-in
that it starts vibrating or buzzing when it's time for you
to be called back to the front of the line.
So, what does this mean in real terms?
Well, we have to work our way up.
So, let me go ahead and do this first.
In server-1.js, let me first simplify the code
so we can take baby steps toward a more compelling problem.
This is the exact same program that I wrote before.
But what has been changed?
There's sort of a slight syntactic difference
between this and version 0 a moment ago.
What jumps out at you if you recall?
Yeah Cynthia [assumed spelling]?
[ Inaudible Remark ]
Yeah. So now, we have a line of function being passed in.
We've gotten rid of the sort
of uselessly named handler function.
Useless only in that before even calling it in one place,
I don't really need to waste time giving it a name
and making it harder to read the code top to bottom.
So, let's just declare inline is an anonymous function.
And I'm doing two other things.
I'm making better use of dot notation.
So like in jQuery, a lot of node methods can be chained together.
So that once you're done calling something, you don't have
to wait to a new line and call another method,
you can just chain them together.
And so in this way, we can really tighten this up.
So, this is literally a web server in five lines
of code total unlike the--
unlike what you might normally have to do to set something up.
If I go into server 2 now, let's do this.
In server 2-- actually let's come back to that server 2.
Let's now open up async-0.js and address that problem at hand.
So first, let's go ahead and open
up async-0.js in the browser.
So async-0, let me go back to the browser.
Hit reload.
And now, this is kind of error message.
Indeed I'm seeing a 500 in Chrome's inspector.
But let me more precisely request hello.txt.
OK. So, this seems to work.
So async-0.js doesn't seem to serve up something for slash.
It has no default file support.
But if I explicitly request hello.txt,
that seems to be supporting.
Why is that?
Well, what I've gone here
and done is implemented a super simple web server
that demonstrates where asynchronicity can be useful.
And that is implemented as follows.
First, I'm using the HTTP module again,
but also FS which probably stands for?
In general in CS, file system.
OK file system.
Hence forth FS, file system.
All right, so what does this give me?
Functionality related to files like getting passed,
opening files, writing directories, reading directories
and all of that kind of stuff.
So now notice, this code is the same as before,
create the server, passing in an anonymous function.
This is kind of arbitrary.
This is not a very secure web server.
In fact, you could access most any file on my hard drive
or on the server's hard drive by executing this code
because I'm just blindly assuming that I'm going
to grab whatever the user requested in the URL.
And I'm going to prefix it with dot
so that I'm marginally being safe
by saying whatever file they can request has to at least start
in the current directory.
Of course there's a threat here.
'Cause if they instead include what?
In their path, they can kind of work around that too.
Dot, dot, right?
So, if the user just put dot, dot in the URL, in theory,
they could start getting my-- and say password file.
So, this is not meant to be secured,
it's meant to be simple.
So here, I have a variable which is the concatenation of dot
which is present directory and the request URL
which we saw before is like slash or /hello.txt.
So now, it gets a little more interesting.
First, notice the bottom.
I'm listening on the same port as before.
So the real interesting work is inside of here.
Every time a request comes in by nature
of this code, what am I doing?
I'm calling file system's read file method,
passing in the path that I want to read.
And now, this is what's interesting here,
this is by implementation in asynchronous method.
You cannot get a return value from read file.
In fact notice, there is no left-hand expression
to the left of read file.
It does not return a value.
Rather, it calls a callback function when it is ready
to give you back an answer.
So again to be clear, whereas in yesteryear,
in many programming languages, if you wanted
to read a file case in point PHP,
file underscore get underscore contents,
you have a left-hand expression in all the value after--
before the equal sign, that means you're assigning
to that variable the return value of that function.
You can do that in node.js, but you typically have
to call explicitly synchronous versions of functions like,
I think it's read sync file or sync read file.
I forgot how they named it.
And that would give you a return value.
But if that file is on some remote file system
or disk is just naturally slow, it could take 10 milliseconds
or 2 seconds for that file to actually come back.
Meanwhile, no other web visitors are being serviced
by your websit.
You're blocking.
That's what's called blocking IO, input/output.
So here, this is much smarter.
Because what node.js is going
to do upon interpreting is the following,
it's going to call the read file method,
try to one up the file who's got a path specified by the value P.
And then if and when it's ready to give you back the contents
of the file P, it will call a function whose signature is
by convention the following.
Two arguments, the first of which is maybe an Error object,
capital E, it's an object called Error or Null
if there's no such error.
And the second argument-- take a guess-- is going to be what?
It's called data obviously but what is data more concretely?
>> Contents?
>> The contents of hello.txt in the example I pulled
up in my browser a moment ago.
So in other words to read file and many node.js functions
like at do not return values.
They call callbacks and pass
to those callbacks what would have been traditionally the
return value.
The upside of this approach is
that you might call read file a T0.
The callback function might not be called one tick later
so to speak at T, it might be called a T1000,
a thousand ticks later.
But the point is that the rest of the code in this file,
if any would immediately be executed while node.js
and while the file system figures out how to read
that file and get it back to you.
So you create this--
so effectively the illusion
of parallelism while letting slower running processes is not
block the important stuff, the part that servicing users.
So, how do we handle this?
This is a very common node.js paradigm.
And there's way just to simplify this is we'll see before along.
I first checked if Error is not null.
So, if it's not false then there was an error.
I don't know what that is, maybe the file doesn't exist.
I didn't have permissions.
The pathname is wrong.
Any number of things could go wrong.
For now, I'm going to arbitrarily return the 500
which is internal server error.
Something went wrong.
I don't really care to diagnose it.
So, let's just tell the user it's broken.
And then, I'm going to do res.end,
and this is shorthand notation.
Recall that last time I did res.write
and then I did res.end.
If you only want to send one line of output,
you can just do it all at once with res.end with an argument,
and that's going to send whatever the error message is
inside of this object to the browser.
It was pretty arcing recall a moment ago.
I have no idea what this meant at first glance.
But when I requested a file that didn't exist--
oops, we need to run the server again.
When I requested a file that didn't exist, EISDIR,
so something about it being directory,
if I do some random string there,
apparently that means the file doesn't even exist.
And that's because my code is simply saying to write
out whatever the Raw Error message is,
so not very user friendly but at least I'm handling it.
Else, if it wasn't an error what am I doing?
Same thing as before spit out a 200 OK, a plain--
text/plain mind type and then spit out the data.
And that's why I'm getting the contents of hello.txt which just
to confirm if I looked at hello.txt,
it's literally just hello, world.
And if I changed this hello, world, save the file,
rerun the server, reload the page.
Now, I get that version.
So, I've really just reimplemented a web server
as is existed for many years but using node.js.
But we can do this even more cleanly.
Let me open up async-1.js.
Now, notice I'm adding another module this time,
apparently the path module.
Now, this is a good opportunity to look
at what the documentation looks like.
Node.js is documentation.
Like PHP I think is actually pretty good
and straight forward.
If I go to node.js and Google and search for node.js path,
what you'll see usually is a direct link to a URL
that I put up here a moment ago.
So /api is the official place to go for documentation.
And what you'll see at the top
of node's official documentation is all of the methods and
or properties inside of this particular module,
one of which is called join.
And join is the helper function that's going to allow me
to not bother with all the pluses.
And it has the added bonus as you'll see
from the docks is it also normalizes the resulting path.
So, if the user or you have dots or dot dots or any combination
of those kinds of relative paths, among the upsides
of the joined method is that it's going to clean all that up
and give you a canonical path without any
of those dots or dot dots.
So, it's a good thing in general for security at least
if you're checking the return value which I'm not
in this particular simple case.
But I did want to use it.
So, I now create the path a little more programmatically
with path.join instead of Raw concatenation.
So, that's a little cleaner than before.
And now notice I'm being a little more intelligent rather
than just blindly try to read the file,
I'm going to actually call fs.stat.
So, if you're familiar
with low-level C functions and C, even PHP.
A lot of libraries have this function stat returns
essentially statistics on a file, the file size,
the permissions, the name and things like that,
and also implicitly if the file exists or not,
and if it's a file or directory
or symbolic link or something else.
So now notice, I'm calling fs.stat.
And then apparently according to the documentation,
I should get back in Error object
or Null followed by a stats object.
But let's check this, node.js.fs.
Here is the file system documentation.
Let me look for stats.
There's a lot more of functions here.
Oops, that stat sync, fs.stat.
So here, it's asynchronous stats (2).
That's meaning if you remember from main pages,
chapter 2 of the main page,
that means this is literally just a node implementation
of the low-level system function stat.
So, the callback gets two arguments, error and stat
where stat is an fs.stats object.
So let's see what this object is supposed to look like.
Let's click the hyperlink and I see that.
The stats object contains apparently some helper method,
is file, is directory, is a bunch of other things.
It's the "is" file that I care about in this particular case.
So here I go.
If there was an error, then let me just bail this time
and assume.
If there's an error, it was probably a 404 file not found.
It could be something else
but I'm being a little lazy here just to focus
on the more interesting details.
But for the user's purposes, file is not found,
if there was any error stating the file.
Otherwise, let me check if the file is indeed an actual file.
So if it's not a file, it exists.
There's something there but it's probably a directory
or maybe a symbolic link
or something else that's funky on the file system.
Either way, the user shouldn't see it.
So now, I'm just going to spit
out conventionally unauthorized 403.
But again just a convention,
I could have used something else in theory.
And then lastly, let me try to read the file.
So, let me scroll down.
And now notice this is where the code can get a little messy,
notice that I'm calling fs.readFile passing
in the same path, same callback as last time,
so the previous version.
And then if I'd find--
if I don't find it, I spit out of 500.
And if I do find it, what line are we going to see here?
We're going to see the fs write header 200 probably
and a res.end sending the actual data.
But notice this.
And this isn't demonstrative of the worst case scenario.
But I have this stat call here than I have some stuff.
Then, I have another asynchronous call here,
so more indentation.
So, just kind of extrapolate if you could from here.
What problem tends to arise with the language like JavaScript
in this environment where you don't have return values
but rather you have these callbacks.
And of course, this is just a stylistic thing the fact
that I keep indenting.
But take this to the logical next step.
Suppose there were one or two or three other functions
that I needed to execute that were by nature asynchronous,
and therefore you just kind of keep indenting to handle them,
to handle them, to handle them.
You get sort of callback hell as people call it
where your code starts to get very wide
and frankly really hard to read.
As it is, I can sort of barely tell that this is sort of a flow
that has this sort
of stylistically angled thing going on here.
So, this isn't ideal because this can very quickly become
unwieldy, even though two asynchronous calls not
such a big deal.
So, we could avoid this, right?
You may have glimpsed that I misclicked a moment ago.
In the documentation, you know, it looks like there is statSync.
And statSync does not take a callback as an argument.
It takes just the path because it apparently does what?
It returns an instance of fs.stats.
So this might be your first instinct, right?
Especially if callback functions
and asynchronicity is a little new to you, frankly,
the easiest approach is probably just avoid the problem all
together, go back to sort of CS101 style programming
where you call function or method, returns the value,
call function, returns the value,
function, returns the value.
And I could use therefore fs.statSync
which is literally the same but it's a synchronous version
which means it returns the value.
It doesn't pass a value to a callback.
But why would that probably be a suboptimal workaround to resort
to synchronous functions?
Yeah?
[ Inaudible Remark ]
Exactly, it takes a long time.
You're just slowing everything down.
Because much like Shake Shack or Tasty Burger, if they got rid
of those buzzers and made you, the customer stand at the front
of line until your food is ready before even taking the order
of the person behind you obviously
through put slows down.
People start leaving, you sort of draw packets.
You can make any number of analogies here.
But in short, it's probably not a good thing
for business or for the server.
So asynchronous code is typically good at least
in this case, but it definitely starts to cause some angst.
And in fact I dare say when first writing this stuff,
it'll take a little bit of getting used to.
So, let's start to equip you with some libraries
and techniques to make this a little easier.
So, one of the most common libraries are popular libraries
these days, this one called async.js.
And like a lot of node.js libraries or modules,
these are all open source.
They almost all live and get hub repositories which is kind
of become the de facto place to store these things.
And then there's a whole infrastructure
for installing these things called NPM, Node Package Manager
which if you're familiar with EvanTube is kind
of like app or app get.
If you're familiar with Red Hat and Fedora
as in the appliance, it's like yum.
But it's a node-- it's a package manager just
for this particular environment.
So, we can download and install things like the async library
and also another one called the underscore library or module.
But these as far fs, HTTP, path,
those are all come built in to node.
So if we go to the API docs, you'll actually see that built
into node you get for free a whole bunch of modules.
But plenty of nice people on the internet have made dozens
if not hundreds of other libraries
to do things better or differently.
So, let's take a look at how this library works.
So, most of this code is identical for the moment.
I have a path being created up top.
And now I'm calling async.series.
So the async library, it's just a library that allows you
to pass or raise typically of functions to get called one
after the other just to kind of avoid that indentation issue,
and really just the mental angst that will invariably arise
at least when you first dive in to this on your own
with programming asynchronously.
As in aside, if you have taken 161 and you've dealt with locks
and raise conditions and all of that, asynchronous code
and an environment like node.js is actually much,
much simpler arguably
than actually writing multithreaded code.
Anytime you have multithreaded code,
you do have raise conditions.
You have to worry about two threads containing
for the same resources disk or memory.
The beauty of JavaScript
in node.js is there's literally only one thread,
which means the browser
or the server can only do one thing at once.
It's just up to you, the programmer
to keep a mental model for how you sort of queue things
and figure out how to order your code.
But you never have to worry about raise conditions
in quite the same way at least with Raw code like this.
So, it's a little hard to grack here.
But-- So let me open up the docs for just a moment.
The async.js library which similarly is very googleable,
it lives in the GitHub repot like a lot of them.
Don't think it's sketchy, it's not.
Let me scroll down to the Read Me here.
So, the async library provides a whole bunch
of methods inside of it.
For instance, there's a method called each,
which if I click this just to see its docs for a moment,
this is a function or method that allows you to do something
like a four each but in parallel.
They're all going to happen potentially in parallel.
And the method each is only going to return to you when all
of the iterations are complete.
So maybe they happen one after the other.
Ideally, they happen essentially in parallel.
But the method doesn't call you back.
It doesn't buzz your buzzer until all
of the elements you have iterated over have completed.
So, it's just a nice way
of avoiding using a simple four loop
but actually doing something asynchronously.
But now more directly related to this example,
notice there's this series method.
And let me just pull up a simple canonical example.
So the async libraries, series method takes in as implied
by the square brackets in array.
What are the data types of the elements
in this array based on a simple example?
This is an array of functions.
So in C, you would call them function pointers.
In JavaScript, there are more properly references to functions
or anonymous functions.
And this just means, arrays
of course are ordered from zero on up.
So, they have maintained an order which is good
for a series, 'cause series of course means do something
in order not in parallel.
So, this just means that this function will get executed,
then this one, then this one, this one, then this one,
however many there are
until finally the optional callback is called.
So, notice the paradigm here.
And even though this is one guy's library,
it's representative of the very common JavaScript paradigm
of again using callbacks.
So, notice what you do here.
In the first function being passed in via this array,
you defined an anonymous function just with function.
But notice that apparently according to this documentation,
that anonymous function should take an argument callback.
That is going to be a pointer or a reference to a function
that you should call when your code is ready to return a value.
So again, unlike for just typically procedural programming
where you're used to returning values immediately
that one difference with using a library like this
in asynchronous programming more generally, is when you are ready
to return a value from a database, from a file,
from an arithmetic expression, it's up to you
to call the callback function.
And the nice thing about this library
if we read the docs more carefully is that,
if and only if all of the callbacks area called
without an Error object, will the whole thing succeed?
So in other words, if there are 2,
if there are 10 anonymous functions
in this array therefore in this series,
only if all of them succeed,
will the final optional callback be considered successful?
If anyone of them fails, every function
after it will not even be executed.
So, it's a nice way of sort of having a daisy chain
that aborts prematurely if something goes wrong.
So to see this in context, here is how we might re-implement
that previous program.
I get the path as before, so this is the easy part.
I copy paste this skeleton code
from the documentation there async.series open parenthesis,
open square bracket.
And now notice I have one function in this beginning
of a second, we'll see where we go from this.
And now notice, it's a little complex at first
but focus just on it line by line.
Fs.stat means get the statistics or what not of that path.
Call this callback when ready.
This code is the same as before.
If there's an error, there's one difference now.
Again, the very common paradigm in node.js programming is
if something goes wrong and a callback needs to know
that by convention, the first argument to a callback is going
to be no, if all is well or a reference to an Error object,
capital E. It's like an Error class that exist globally
but more on that some other time.
So by doing this, if there's an error, what's the implication?
Well based on what I said the series does,
is if anything goes wrong, we just kind of want
to abort the whole series of anonymous function calls.
So, it suffices for me to just return callback passing
in the Error object.
Because if stat gave me back an error,
I could create a new Error object of my own,
but I don't really care to,
I just want to pass whatever the error is that actually happen
so I can pass it to this callback.
And just to be clear, the return isn't strictly necessary.
I essentially want to do this but I wanted now do "return;
// so that no more code here executes".
So again another common convention in JavaScript,
even though you're not returning a value per se,
you want to pass the value to the callback function
but then you want to stop execution
of the function you're in, the trivial way
to do this is just to call return here.
But there's nothing wrong,
we're just doing return callback error even though it's going
to return in undefined value.
All right, this does not return a value most likely.
All I care about is a boarding further execution.
So, my conflation of these two lines is just a stylist
to convention just to have the number of line
of code I just wrote from 2 to 1.
So what else?
If there's not an error--
actually to be clear I could also avoid
that by doing if else.
But again, another common paradigm is check
for your errors up top and then just return rather than continue
to indent your code with elses and elses and elses.
So if it's not a file, now, you know,
I want to handle this a little specially.
So here like in Java or C++ or a few other languages,
here's how can instantiate an object to type error passing
in a default message of not a file
and this is just somewhat arbitrary.
But I'm signaling an error of my own.
And what does this last line presumably signify?
All is well.
If you pass in null for the error parameter, that just mean
by convention all is well.
So, that means what will happen logically?
If null is passed to the callback
that means this anonymous function has succeeded
so to speak.
So, what should the series method precedes and now do based
on my verbal definition earlier?
[ Inaudible Remark ]
Move on to the next one, right?
If it had returned a non-null value, it would just abort
and no more anonymous function would get called.
But because it hasn't, then this will get called next.
So, the logic in here is pretty much the same as before
and we'll see how to clean this up further in a moment.
I realize this is kind of a lot
to absorb all verbally and visually.
But now notice, the second anonymous function that I want
to execute in series is to try to read the file.
Call this callback when you're ready.
If there's an error, just signal it by way of the callback
so that the rest of this stuff aborts.
Else return null.
But why am I passing in two arguments?
Well this time if I read the file and get back
as a variable called data,
I want to not only signify all is well by returning null
for the first argument.
I want to return the actual data as the second argument.
Because if I read further in the documentation,
notice this last chunk of code square bracket means that's the
end of the series.
There were only two anonymous functions in this series.
If there was an error here, then I know that one of the links
in this chain so to speak failed.
So in other words, this error is going to be an Error object
that is null if any of these guys failed.
And if that's the case, I'm just going to bail out and I'm going
to say 400 which means request fail,
that's very generic error message.
And then, I'm going to print out the error message.
So, I'm not bothering to be super anal this time,
I'm not going to distinguish between 500 and 404 and 403,
I'm just kind of blindly wave my hand
and say something went wrong.
But if nothing did go wrong,
I'm going to send this res.end passing this data.
Now this looks a little cryptic.
But again if I read the documentation,
the second argument to this final, final callback,
the guy that's only executed once the series is done
executing or a portion there of, this is going to be an array
of all of the second arguments
that were passed to the callback.
Now, it turns out that the only link in this series
that actually return to second argument is this one here.
So I'm going to sort of on a leap of faith simply use suppose
for the moment that last is a method
that gives you the last elements of an array.
Because this array that's being passed
to me has two indicies, zero and one.
It's just zero has no value because this guy returns--
does not pass in a second argument but this guy does.
So results bracket zero is nothing,
results bracket one contains what,
if you've been following along up to this point?
The file, the hello, world content presumably,
so that's how I actually print it.
And let me finish one detail here.
If I do this sort of old school, if I want to get
at the last elements, if I could do results[results.length-1],
that's sort of the old school way
of accessing the last elements in-- or zero index array.
But as in the side, recall that I had this library
up here underscore which by convention is just called
literally an underscore character which is not special,
it just looks cool like dollar sign does for jQuery.
This is just a helper method underscore dot last
that does exactly the same thing.
And if you've never used it before underscore JS both
for client side coding
and server side is a wonderfully useful library
that as many people described it like jQuery contains all
of the methods, people wished came with JavaScript itself.
OK.
>> So, like pretty to me and I was watching in the series,
you have like callback as an argument?
>> Yes.
>> Like so when you actually like push that in,
and like what does it mean when you just have
like callback and then do like--
[ Inaudible Remark ]
>> OK, good question.
So, let me pull up the async main page here
or the documentation on GetHub.
So this is the canonical structure.
If you're call using this particular method series,
there's two big parts to it.
One is an array of anonymous functions
and two is a final callback function that's actually
executed at the very end of the series.
Now, if we zoom in a little closer on the first
of those big things, the array of anonymous functions
by requirement of this guy's documentation has
to be an anonymous function that takes
in one argument called callback or foo or bar, it doesn't matter
but he's calling it callback.
And this is sort of your buzzer that Shake Shack hands you.
This is the means by which you can return a value
to the customer because you can't just do literally return.
You have to do it by way of this callback.
Because if inside of this function is some slow running
code like query database, read the file from the file system,
you don't want to wait there and block everyone else,
you want to call the callback.
So, this is literally the name of the argument.
But like in C, you have function pointers.
In Java you have reference system methods
and the same here in JavaScript.
This is a variable but its type is function.
So simply by writing its name whether a callback or foo
or bar, then open parenthesis and close parenthesis,
you're executing that on that function.
And passing a null which means null error and one
which means this is the data that I want to pass in.
And then the chunk to be clear, this is another callback.
And it's not called callback,
it just conceptually is a callback method function
because it is called by definition
of this author's library when the entire series has completed
or subset thereof if an error has happened sooner.
So, name of callback function, calling callback function,
name of callback function, calling callback function,
different callback function all together.
>> We now have like define callback?
>> No, because this guy will pass into your array
of anonymous functions,
a pointer to the code he wants to execute.
Exactly, all right.
So, please say that the code gets a little simpler.
So, it can.
And if you're like me, take comfort in at least knowing,
it takes a while to get used to this.
But we can clean this up a little bit,
not to throw too much at to you but here's another variation
and its using another method
in the same library called waterfall.
The upside of which is unlike series where each
of those anonymous functions executed essentially
independently of each of the others.
Waterfall like the name suggest allows the uppermost functions
to kind of pass in values to the lower function,
sort of like a cascade of water.
So the upside of this is that I can kind
of use this to my advantage.
In async.waterfall, notice the following.
I can just call fs.stat passing in the path
that I want to get statistics on.
And then remember before I had an anonymous function
that had two arguments err,
esults and then I called the callback function manually?
In other word is just to be clear, recall that earlier
in async 2, I did all of this nasty work.
I called fs.stat passed in P,
declared my own anonymous function.
I then checked if error is not null then I did this,
else I did that, the whole beauty of following conventions
like in node.js is that callback functions in general are meant
to take at least one argument, an Error object followed by zero
or more useful values.
So notice the paradigm here,
this callback function I'm declaring follows exactly the
paradigm that this guy's async library does.
Which is to say this, why am I implementing my own callback
method when the author of this library is literally handing me
on a platter so to speak, a callback function I can use?
So, I can just pass in the reference he's given me
so that immediately, my several lines
of code become one line of code.
Now, where do we go with this?
The next function that I want to execute,
the next anonymous function in this array
of functions does the following.
Notice first stat is the first argument.
So something has changed already.
Now, this guy who wrote the library--
and I'm saying guy because it is a guy.
This guy who wrote this library is documentation guarantees
that if this function here passes me back an Error object
or null followed by a coma separated list of other values,
he will make sure that those other values are handed
to this anonymous function in order from left to right.
And what used to be just a callback function alone simply
becomes the last such argument.
Now, I don't know who I'm focusing on just you know.
But now, what's the take away here?
So, we know from the documentation
or the prior couple of examples
that fs.stat ultimately expects a callback with two arguments,
the Error object which is an Error object or null followed
by a reference to stats object.
So if I think about that, Error object coma stats object,
that fits in the paradigm of this person's library.
So, I can simply say because I no the second argument
that it's -- that's going to be passed by fs.stat
to the callback is err,stats by definition of this library,
I can put the second argument's name here
or whatever I can rename it
if I want followed by the callback here.
So, I can pass one value from here to here.
Now, all of this code though admittedly somewhat cryptic is
at least copy paste for the most part from before.
The only difference is notice here I'm declaring an Error
object and now I want to get a little fancier.
I actually want to know what the error was, so I'm going
to tuck inside of this object a property arbitrarily called code
so that I know that this is not a file
that should be unauthorized, it's an HTTP 403.
Let me remember that before I pass the Error object
to the callback.
And then lastly try to read the file, so in this case,
the waterfall, I've broken the code from two big steps
into three smaller steps.
Notice the beauty here,
I can call fs.readFile passing in the path.
And then the hard part mentally, is I just pass
in the guy's callback.
The thing he's handing me, I'm going to pass to fs.readFile.
Because we're all adhering to the same conventions,
first argument to a callback is an Error object or null followed
by a coma or separated list of useful stuff.
So, what that means now and if I read the documentation I'll know
this, the very last callback, this guy here outside
of the square brackets is going to be passed in Error object
or null which I should check for as always with this code here.
And then by definition of this method
in the guy's documentation, the last value returned
from the last method in my anonymous array--
my array of anonymous functions.
So, what does read file return
and I'm using a return loosely now.
I mean what does read file pass as arguments
to the callback method its handed?
Two arguments, first is an Error object or null,
that's almost always going to be the answer.
And the second thing is going to be what for read file?
The contents of the file, data as we called it earlier.
So, by simply declaring err, result,
and check for error this is sort of boring now.
Else, I do res.end passing in that result.
This will undoubtedly not sync in perfectly
until you actually write it yourself.
But for now, take away at least the fact
that there is apparently this common paradigm, whereby if we
and authors of libraries all sort of stick
with this convention of callback methods.
And the first argument is an Error object or null.
And the second and third
and fourth objects are things we care about and we sort
of follow rules and documentation.
We started with code that honestly is pretty ugly.
And even though the most recent example is frankly kind of hard
to wrap your mind around, it's at least visually,
looks like it's much tighter.
And once you get comfortable with it, it's so much easier
and it's so much less prone to bugs than that previous example.
So, let me demonstrate one last thing here.
This is version three.
And-- No, let's leave this one alone.
Let me go into a couple of other last things as teasers.
All right, so in server 2.
OK. First, any questions, I know this is a lot
but you wanted more instructions, so?
You didn't say good instruction necessarily.
Yeah?
[ Inaudible Remark ]
Correct, you're essentially lenient to operating system
to figure out how to juggle all of these balls at once,
reading from a file, reading from a database.
And it's this JavaScript server itself that's single threaded.
And essentially and actually,
there's one picture I didn't throw up,
and it's not necessarily all that enlightening
but maybe we'll give you a mental model.
JavaScript itself and node
in particular has this so called event loop.
Whereby, you can think of node.js, the program,
is literally like an infinite loop.
It's just a wild loop, waiting and waiting and waiting,
looking for tasks to complete.
And the task might be, go fetch something from a database
or here's a value from the database or go get this file
from disk or here's a request from a user.
Any sort of event, just like the browsers event driven,
so as the server side event driven.
And any of those things constitute events.
So someone in node.js, just wrote an infinite loop,
a big wild loop, waiting for stuff to happen.
And as stuff does happen, it ends up in a queue, right?
Certainly, a database might return a value.
And a file system, the operating system might return a value
at roughly the same time but there's probably going
to be some ordering to them.
And node.js is going to have essentially a queue
like a big array or a vector, some data structure
that buffers all of those things.
Because it can literally only handle one of them at a time.
So, when you, the developer,
writing asynchronous JavaScript code using asynchronous
function, you're allowing this so-called event loop to go
to the next tick, right?
So, long as you immediately return as all
of these asynchronous methods do like read file and stat,
they return immediately because the callback eventually
gets back.
As soon as you return,
that means someone else can get popped off the stock here
or that it can get popped off in front of the queue here.
And so, there is in fact the serialization
of everything that's happening,
even though all these stuff can be happening in parallel
on a multithreaded system.
But node.js itself and the server were running
as one thread.
And the down side of that is t you don't necessarily max
out your computer's capability is as especially
if you have a 16 core or even a 2 core computer
and you're just running one instance of node.
But if you've again taken something like 161,
you avoid a huge nightmare of headaches when it comes
to race conditions and locks and semaphore
and writing truly the multithreaded code,
so upsides and downsides.
OK. So, back to the code here, let me propose that we start
to simplify things a little bit.
We saw server one a little bit ago which looked like this.
So, that's arguably pretty simple.
But just like in the world of PHP, there are frameworks
like Laravel and there's things like Rails and Django,
same thing in the node.js world.
And we'll spend more time on this on Wednesday
and in the next project.
But if I go into a server 2 directory,
notice a couple paradigms here.
So this is-- there going to be an equivalent example
but it's using a framework called express.js,
which is free open source software like Rails and Django,
like Laravel, that's just ultimately going
to be unappreciated today 'cause we've been writing
such simple examples.
But trust us.
This will very quickly become your friend
because it will save you a lot of TDS code.
And a common paradigm for an express.js application is
to have an app.js or server.js file which contains the logic
of your program or at least the entry point.
You can have multiple files.
A node module subdirectory which has the libraries
that you've downloaded like async
and express itself in others.
And then package.json, package.json looks like this,
and you can create it manually or tools create it for you
and it's literally a json file
and the interesting part is the dependencies here.
Just like in Laravel, you had that vendor directory
and you had to worry about packages and doing--
actually updating with Artisan or similar commands,
the libraries you have installed,
similarly with package.json here and you manage the libraries
and the versions that you care about.
So, if I have a package.json, I can simply do NPM,
Node Package Manger install, it's going to automatically look
at that package.json file.
Look and see, do I have the latest version
of all the vendors modules
in a node underscore modules directory here or maybe
in some parent or ancestor directory.
And if not, it's going to download them
and you'll see a whole bunch
of HTTP stuff going across the wire.
So for instance, let me show you the contents
of node modules just to express.
Let me go ahead and boldly delete node modules
so that all I have now is this.
And if I do NPM install, you'll see that it's going to read
that package.json file and we've seen output similar
to this in the Laravel world.
It's downloading a whole bunch of stuff and that's
because express in turn depends upon a whole bunch
of other peoples libraries.
So, all of those are sort of being downloaded recursively.
Until now, if I do in LS again,
there's my node modules directory back
and express as back.
So it's just a way of simplifying package management.
Now, if we look at the app.js file, this is going
to be a reversion to our earliest web server
where we just spit out "hello, world".
But notice the paradigms here,
first we require the express module, then we have this line
of code which you know from the documentation.
You literally treat that module's variable as a function,
so open parenthesis close parenthesis means execute it.
That's going to apparently return something we're going
generally call an app.
How it works?
I don't really know.
I'll let someone else, you know, in the express world write that.
I'm going to now stand on his or her shoulders so as
to make my application running a little simpler.
Here, I'm going to listen on that particular port
that could be most anything.
And here is code that's maybe more reminiscent now
of Laravel and routes.php.
So this is supper simple, I'm just going to specify a route
for slash star, so everything is going to be absorbed
by this request handler.
The paradigm for request handler is its anonymous function
with a request argument
and a response object just like before.
And res.send in express means you send the code followed
by whatever you want to send.
And of course, you can do something fancier
by actually sending files or HTML
or dynamically generated content.
But for now, all we did was spit out hello, world.
If we go into server three, this is even fancier just
to show you some functionality.
And we'll show you an even sexier version
of this on Wednesday.
But if you've ever heard of Socket IO maybe,
so as I think Jonathan or someone said earlier,
one of the things node is really known
for is its real time behavior, right?
Think about PHP in MySQL, if you were to implement a chat server
in PHP whereby two people could open a browser window to foo.com
and then start IMing each other, Alice in one window,
Bob in another so that each of them sees his
or her messages in the other window.
How would you do this in PHP and MySQL?
Using or not using Laravel sort of immaterial, you can have
like an index.php file.
And you got to have-- in some cases it's got to spit
out of form, so there's going to be an HTML form
that probably submits not via normal form submission
but Ajax probably, right?
So, an on submit handler, so you type into a text field,
you hit enter and then it gets sent to the server via Ajax.
What do you then do on the server?
So, you've got index.php
or something dot PHP that's received in HTTP parameter
from the user, Alice's or Bob's instant message, what do you do
with it in order to propagate it to Bob or Alice, respectively?
I mean you literally have the tools with which
to do this in your min.
So like what would you do?
You have one minute to implement this program.
Yeah?
[ Inaudible Remark ]
Perfect. Right, so you've got a database.
We know a little bit about MySQL.
So, you have a table that's messages,
maybe there's a times stamp, a user ID,
the body of the message itself created that,
updated that and all of that.
So, you store in a database.
And suppose Alice sends the first message, how does Bob get
that message now from the database?
>> It might be some Ajax response that's constantly going
back to the database top get the [inaudible].
>> Exactly.
So Bob's code who's code is the same as Alice is just sort
of a symmetric relationship,
Bob's browser has some Ajax code that's probably maybe every 30
seconds pulling the server via Ajax sync,
are there new messages?
Are there new messages?
Every 30 seconds is going to be kind of suboptimal
because he has to wait even
if Alice literally just sent the message.
So, Bob's browser could every second hit the server.
But that means Alice's browser is hitting the server
every second.
What about Charlie [assumed spelling]
and David [assumed spelling] and Edward [assumed spelling]
and every other letter of the alphabet?
What's the problem of this approach?
A lot of hits excessive--
I mean you're just effectively DOSing your own sight
or DDOSing, Distributed Denial Of Service attack
on your own site, by having all
of these users run JavaScript code that's just pinging the
heck out of your server even if arbitrary number,
80 percent of the time no one has said anything
in the chat room.
But you're just checking to make sure of such.
So PHP in a lot of languages are just not good
for real time communications.
Because in PHP recall there's no central memory, right?
You have session objects which creates the illusion
of central storage but that's on a per user basis.
You don't have global memory like you do in a Java Servlet
in familiar or in other frame works like that.
Node.js though, you do have global memory 'cause you have
one server and that' can remember anything it wants
about all users.
And you might still have a database.
But the nice thing about node.js too is that it's much better
than something like PHP and creating the illusion
of handling multiple things at once.
And in fact as in aside, you can implement chat servers in PHP,
but you would typically do something called long polling
whereby you don't ping the server every second.
You ping the server, the server doesn't respond to you
for upwards of 30 seconds, it literally sits
in a loop waiting and waiting.
And the server checks if there's new data in the database
and only once it you sees, "Oh, here's a message from Bob,"
does it reply to the HTP server?
So the effect in your browser is that the IE icon or Mozilla
or whatever just keeps spinning for 30 seconds at a time.
But the upside is, you don't have 30 connection requests
in 30 seconds, you have one.
So it's called long polling.
But even better in modern web browsers is something called
WebSocket, which you take the CS143,
you can effectively make a TCP connection from a clients
like a browser to a server and then hang on to it
without using nearly as many resources
as HTTP might traditionally do.
And Socket IO is a node.js library
that makes it much easier to make the socket connections
or illusions there at for old browsers
so that you can implement this real time functionality's.
So, here is an example.
This stuff up top gets a little more complicated
but it's mostly copy and paste from socket.io's documentation.
Here's now a more precise request handler.
If the user request a slash, what file am I going
to be apparently serve up to them?
Index.html.
And there's some new stuff here stream
which I'll show you in just a moment.
But this is just another way
of grabbing a file a little more efficiently
than just doing fs.readFile.
It's a little smarter especially for big files.
So long story short, these lines just to serve
up a file called index.html
which for now assume contains the HTML form by which Alice
and Bob might intercommunicate.
Lastly, io.sockets.on, so this comes from this line up here.
So, I'm just reading the documentation io.socket gives me
access to a so-called WebSocket with a browser,
between the browser and the server.
I'm listening for special event connection which means
when the user first hits the server trying
to open this connection, I'm going to call this call back.
And now, I'm going to do the following.
Every five seconds, what I'm going to do?
I'm going to emit or broadcast if you remember scratch,
the graphical language would that a broadcast blocks?
So, you're going to emit
or trigger an event called arbitrarily from server.
And it's going to contain a message Ping
and the current date.
So, this is an actual chat server that Alice
and Bob can use, but it's sort of an automated chat server
where the messages are just sort of sonar pings.
It's just date at times that are being sent every five seconds.
So, if I actually run this thing-- and that's it.
To be clear down here, notice this is just logging down here.
So, let me turn a blind eye to that.
Let me do node of app.js.
Let me go to my browser.
Reload the home page here.
[ Pause ]
And let me close the inspector.
Every five seconds, I have a demonstration even though not
interactive for human
of something that's happening asynchronously.
In the browser notice, there's no spinning icon.
It's using a fancier feature of Chrome in modern browsers
of maintaining a socket connection underneath the hood
and it's what's called generally a pub/sub model,
publish/subscribe model, where we haven't done
that quite explicitly here.
But what's nice about this general pub/sub paradigm is
that you can have one publisher.
In this case the central server and all
of the individual browsers are clients.
Alices and Bobs of the world can subscribe to it,
so you can relay messages among any number of users.
And even though again we're not seeing interactivity,
we had maybe 12 lines of code just to do this.
And it's probably not a leap to imagine how you might whip
out the index.html file that has a true HTML form,
little bit of jQuery code with Ajax that doesn't send a daytime
but just sends whatever Alice or Bob type to the server
and then the server will relay it out.
And I promise to glimpse at one last thing just
to tease you with this.
If we go into stream zero and one,
you'll see code that's just a little different here.
Just so you've seen it, this is an alternative
to what I called the fs.readFile method earlier, whereby,
you can tell node.js, "Go read this file into memory.
But if it's big just give me a chunk at a time."
And you might know from CS165
or 161 the file systems have different
performance properties.
You might want to read in blocks of 512 bytes
or 2 kilobytes or whatever.
This is an optimize way of getting back of file iteratively
so that you can spit it out a little more quickly
to the browser or to whoever the end client is.
So huge amount of content today and we're going to dive
into more detail on Wednesday with Tim [assumed spelling]
in particular looking at how we can translate some of the ideas
from the first half of the course Laravel and models
into a library that he himself wrote called Bookshelf.js
which is become increasingly popular in the community
because it gives you most of it,
if not more than the functionality of eloquent
which recall is that library insight of Laravel,
so more on that and more how
to develop full fledged apps on Wednesday.
We'll you see then.