Node.js Video Tutorial by Ryan Dahl
Windows is very important… just like PHP. —Ryan Dahl
This is a intro to Node.js by its creator Ryan Dahl. It is a very good. You should watch it. I added annotations and his code snippets, so you can actually try it out.
The video is one hour long, but to really understand, you'll need to do hands-on coding. It'll take 2 to 3 hours. Also, you do need to have experience with JavaScript. 〔see Xah JavaScript Tutorial〕
Here is the code snippets shown in the video. I've run and tested them.
The “process” Object
process
is a global object in Node. Here's some use of process
:
// some example use of process object process.stdout.write("rabbit\n"); // prints rabbit console.log(process.version); // v0.10.24 console.log(process.env); // prints out environment variables in JSON format console.log(process.pid); // 9512 process id // force exit process.exit()
Save the file, for example as xyz.js
, then run it in terminal node xyz.js
.
you can use process to get node version, environment variable, process id, command line arguments, read/write to {stdin, stdout, stderr}, etc. process
Asynchronous Hello World
setTimeout
and setInterval
are used to demonstrate asynchronous nature of JavaScript and Node.
// after 2 secs, print setTimeout( function () {console.log("two"); }, 2000); console.log("one"); // prints “one” first, then “two”
The point is that the setTimeout is not sleep. The program doesn't halt. For languages that have “sleep”, when sleep is called, the program halts and doesn't do anything else. JavaScript doesn't have “sleep”. This is the async nature of JavaScript, and node.js takes this idea further.
// print every 2 secs setInterval( function () {console.log("world"); }, 2000); console.log("hello");
Note: Node's setTimeout
and setInterval
are based on the same functions implemented in web browsers. These are technically not part of the JavaScript language, nor in DOM. They are functions in Browser, called Browser Object Model. setTimeout(cb, ms) 〔see Browser Window Object〕
In node.js, “everything” is async (aka non-blocking), similar to the setTimeout
and setInterval
. Typically, a function that do things such as {reading file, handle request, query database}, takes a function f as the last parameter, and this function f will be called when it is ready. f is called “callback” function.
For example, to read a file in most lang, you do “myContent = open(path)”, then you do something with “myContent”. In node.js, it'd be like this “open(path, funcName)”, and when the file content is read, your function “funcName” will be called and the file content is passed to your function as parameter. While Node is opening the file, it immediately runs other things, so it doesn't “block”. Example:
// example of non-blocking (async) reading file datavar fs = require('fs'); // load file handling module fs.readFile("/home/joe/xyz.txt", function (err, fileContent) { if (err) {throw err;} else { lineCount = fileContent.toString("utf8").match(/\n/g).length; // count lines console.log(lineCount); } });
the fs.readFile
method reads a file, and when it is ready, it calls the function you gave it. The point is that, it doesn't halt while it's trying to access the file.
fs.readFile(filename, [options], callback)
Note: not everything in node.js is async. There are some functions that's synchronous, because it's just practical that way.
For example, there is a sync version of file reading named fs.readFileSync
.
fs.readFileSync(filename, [options])
Simple HTTP Server
Here is a simple HTTP server.
// node.js simple http server var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('hi there\n'); }).listen(8000, '127.0.0.1'); console.log('Server running at http://127.0.0.1:8000/');
in the code, the require('http')
loads a module named “http”, and returns a object that serves as a namespace.
http.createServer()
return a web server object.
http.createServer([requestListener])
When there is a request (event), the callback function is called.
The arguments passed to the callback function are request object and response object.
- “request” object is a instance of
http.IncomingMessage
object. http.IncomingMessage - “response” object is a instance of
http.ServerResponse
object. Class: http.ServerResponse
In the response object, you see “.writeHead()” method and “.end()” method.
response.writeHead()
- Sends a response header to the request. response.writeHead(statusCode, [statusMessage], [headers])
response.end()
- signal to server all response header and body are sent. response.end([data], [encoding])
here's a second version that streams out content after 2 seconds. (the point about this is that Node doesn't buffer, because that'd cause delay.)
// node.js simple http server var http = require('http'); var s = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.write("hi\n"); setTimeout(function () { res.end("there\n"); }, 2000) }); s.listen(8000)
Start it by node filename
.
In terminal, press Ctrl+z to suspend current “job”.
Type fg
to resume it.
Press Ctrl+c to exit. 〔see Linux: Job Control〕
To test a server, in terminal, you can use curl -i url
to fetch page. The -i
means show HTTP header in output too.
If you have perl installed, you can also use GET url
and HEAD url
.
〔see Linux: wget (Download Web Page)〕
Here is sample telnet session.
◆ curl -i localhost:8000 HTTP/1.1 200 OK Content-Type: text/plain Date: Wed, 25 Dec 2013 21:42:43 GMT Connection: keep-alive Transfer-Encoding: chunked hi there
you can use apache benchmark tool, to test server performance. Like this
ab -n 9 -c 9 http://localhost:8000/
. The -n
means number of request, the -c
means number of current at a time. 〔see Testing Server Performance Using Apache Benchmark Tool〕
Simple Chat Server (TCP/Socket Programing)
Here is a simple chat server, by creating a socket. 〔see TCP/IP Tutorial for Beginner〕
// -*- coding: utf-8 -*- // simple socket var net = require('net'); var server = net.createServer(function (socket) { socket.write("hi\n"); socket.end("you there\n"); }); server.listen(8000, '127.0.0.1');
This will create a simple server. When user connects, it'll just print “hi” and “there”, then disconnect. net
To test, in terminal type telnet localhost 8000
. (to exit telnet, press Ctrl+], then type help
.)
Here is a second version. This version, will echo back whatever user typed, and won't disconnect.
// -*- coding: utf-8 -*- // simple echo chat server var net = require('net'); var server = net.createServer(function (xx) { // xx is a parameter. It's Node's event object xx.write("hi\n"); xx.write("you there\n"); xx.on("data", function (dd) { xx.write(dd); }); }); server.listen(8000, '127.0.0.1');
Note: in the callback function, the argument passed to it is a event object. The generic event object has a set of methods, but specialized event usually has other methods. Events
◆ telnet localhost 8000 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hi you there th th can you see me? can you see me? what what you you
Here is a final version of chat server. Multiple people can connect to it, and see each other's typing.
// -*- coding: utf-8 -*- // simple chat client var net = require('net'); var socketList = []; var server = net.createServer(function (xxsocket) { socketList.push(xxsocket); xxsocket.on("data", function (dd) { for (var i = 0; i < socketList.length; i++) { if ( socketList[i] == xxsocket ) { continue; } socketList[i].write(dd); } }); xxsocket.on("end", function () { var i = socketList.indexOf(xxsocket); socketList.splice(i,1); }); }); server.listen(8000, '127.0.0.1');
Mashing Things Together: Run Different Things at Different Interval
This script run different things at different interval. It prints every 5 sec, and fetch a google.com page every 2 secs, and also run a webserver and spit out to connected client a string every 1 second.
// -*- coding: utf-8 -*- // demo that Node can do multiple things, each with a different repeating interval // print every 5 sec setInterval( function () {console.log("world");}, 5000 ) console.log("hi"); var http = require('http'); // fetch Google every 2 sec setInterval( function () { console.log("fetching google.com"); http.get({"host": "google.com"}, function (res) {console.log(res.headers);}) }, 2000 ) console.log("bbbb"); // serve web, print every 1 sec var s = http.Server(function (req, res) { res.writeHead(200); setTimeout(function () { res.end("hello world\n"); }, 1000); }); s.listen(8000); // hi // { location: 'http://www.google.com/', // 'content-type': 'text/html; charset=UTF-8', // date: 'Mon, 23 Dec 2013 10:13:24 GMT', // expires: 'Wed, 22 Jan 2014 10:13:24 GMT', // 'cache-control': 'public, max-age=2592000', // server: 'gws', // 'content-length': '219', // 'x-xss-protection': '1; mode=block', // 'x-frame-options': 'SAMEORIGIN', // 'alternate-protocol': '80:quic' } // hi // fetching google.com