Node.
js Basics: An Introductory training
Aleem Ahmad Hashmi Pakistan Atomic Energy Commission(Node.js) @SirHashmi
2009 VMware Inc. All rights reserved
Agenda
1. About Node.js Internal working of Node.js Buzz around Node.js Who is using it What kind of apps are being built Coding in Node.js Sync v/s Async coding (Callbacks) Classes & Modules (CommonJS) npm & package.json Node.js EventEmitters
2.
What is Node.js
Node.js is a platform to build fast and scalable network applications. It is built on Google Chromes v8 engine & implements event-driven, nonblocking I/O model. It is ~80% C/C++ & ~20% JS (APIs) Uses CommonJS module system. Executes JavaScript on the server Built by Ryan Dahl Sponsored by Joyent
Ryan Dahl (Node.js creator)
What is Node.js
What is the biggest advantage of Node.js?
Biggest thing Node.js brings to the table (other than JS, of course) is savings in I/O cost
The cost of I/O
http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/
So how does Node.js save I/O cost?
Node.js saves I/O cost by implementing event driven, Non-blocking I/O model
Event-driven, non-blocking I/O platform/server
What exactly is a event-driven, non-blocking server? How is it different from a multi-threaded server?
Multi-threaded blocking server v/s Event-driven, non-blocking server
Multi-threaded server - Threads are spawned for every connection
User1
i/o request
T1 DB T2 Blocking I/O
User2
i/o request
User3 Refreshes 2 times
T3
T4 T5
FS
User4 refreshes 3 times
T6
T7 T8
T9
Multi threaded server T
Thread Because every I/o is blocking, server spawns a thread in a thread-pool to support multiple requests
9
Non-blocking & Evented I/O (Node.js server)
User1
i/o request
T1 V8
T1 V8 T1 V8 Event loop POSIX Async Threads t2 t1 t4 t3 T1 V8
DB
User2
i/o request
T1 V8
User3 Refreshes 2 times
delegate i/o to libeio
Single thread serves all users
Non-blocking I/O
User4 refreshes 3 times
T1 V8 T1 V8 T1 V8 T1 V8 i/o result returned 2 EL after x time
FS
T1 V8
V8 Thread running JS code (Single threaded)
Node.js
t1 t3
10
t2
POSIX threads doing async I/O (multi-threaded)
Everything except your (JS) code is runs in parallel (by libuv)
Event-driven, non-blocking I/O server
Real-world example of the two designs?
Multi-threaded blocking server (Apache) v/s Event-driven, non-blocking server (Nginx)
11
Apache V/s Nginx: performance
Reqs/sec v/s concurrent connections
At ~4000 concurrent connections, - Nginx can serve ~9000 reqs/sec - Apache can serve ~3000 reqs/sec
Ref: http://blog.webfaction.com/a-little-holiday-present
12
Apache V/s Nginx: Memory usage
Memory v/s concurrent connections
At ~4000 concurrent connections, - Nginx uses 3MB memory - Apache uses 40MB memory
Ref: http://blog.webfaction.com/a-little-holiday-present
13
Saving I/O is great, what else is happening w/ Node.js?
Lets look at community, libraries, buzz around Node.js
14
Other things going on for Node.js
2nd most popular watched on git
15
Other things going on for Node.js
48,000+ libraries/modules/servers
High-level library categories
Web frameworks Routers Static file servers Microframeworks Frameworks Middleware JSGI Connect Other middleware Other Database MS SQL Server PostgreSQL MySQL SQLite
Oracle NoSQL and Key/Value Mongo Hive Redis CouchDB Other NoSQL implementations Miscellaneous and multiple DB Templating CSS Engines Content Management Systems Build and Deployment Package Management Systems Module Loader OpenSSL / Crypto / Hashing SMTP TCP / IP Multiple protocols HTTP FTP E-mail XMPP Other networking RPC Web Sockets & Ajax Message Queues Class systems Testing / Spec Frameworks Wrappers Parsers JSON XML
Command Line Option Parsers Parser Generators Other Parsers Debugging / Console Utilities Compression Graphics Sound Payment Gateways API clients Control flow / Async goodies I18n and L10n modules Boilerplates Continuous Integration Tools DDD, CQRS, EventSourcing Desktop application related JavaScript threads Other
https://github.com/joyent/node/wiki/modules
16
Other things going on for Node.js
Node in Production! LinkedIn, Yahoo!, Yammer, eBay, Twitter etc. >1000 other companies/startups are using it in production All kinds of interesting apps: End-user apps: Real-time apps Mobile apps Web sites Hardware programming (robots!) Platform apps (Servers / Services): Node-http-proxy - Node.js implementation of reverse proxy like nginx LdapJS.org - Node.js implementation of LDAP server itself SMTP Node.js implementation of SMTP server itself XMPP, SSH, RPC, many more.
17
Agenda part 2
1. About Node.js Internal working of Node.js Buzz around Node.js Who is using it What kind of apps are being built Coding in Node.js Sync v/s Async coding (Callbacks) Classes & Modules (CommonJS) npm & package.json Node.js EventEmitters
2.
18
Lets look at the code..
How does async code differ from sync(regular) code?
Synchronous code v/s Asynchronous Code
19
Callbacks Control flow
Use case: Lets say we have an items id and want to get its name from DB and print it
//Synchronous & blocking code function getItemNameById(id) { //blocks or waits for DB return db.get(id); //step 2 } var name = getItemNameById(100); //step 1 //print name in step 3 console.log(name); //step 3 //Async & non-blocking code function getItemNameById(id, callback) { db.get(id, callback); //step 2 //nothing is returned here } //step 3 Some internal function calls the callback w/ result //You create a callback helper function function displayHelperCallback(name) { console.log(name); //step 4 } //pass callback function to consume the result getItemNameById(100, displayHelperCallback); //step 1
Things to note: 1. Async code doesnt directly return anything 2. Instead, it takes a function(callback) & calls that function when result becomes available
20
Callbacks Control flow (detailed version in Node.js)
//YOUR APP var db = require(db); function getItemNameById(id, callback) { db.get(id, callback); //step 2 } //You create a callback helper function function displayHelperCallback(name) { console.log(name); //step 103 } //pass callback function to consume the result getItemNameById(100, displayHelperCallback); //step 1 //INTERNALS OF A DB LIBRARY (HIGH LEVEL) function db() { this.dbConnection = net.connection(); // connects to DB } db.protorype.get = function(id, callback) { var self = this; //step 3 & //step4 is dbConnection.read (below) this.dbConnection.read(id, function(result, callback) { Step 5 self. receiveFromDB(result, callback);//step 101 }); } db.protorype.receiveFromDB = function(result, callback) { callback(result); //Execute callback step step 102 }
21
//step 5 V8 is free to run other functions in the eventloop. //step 5, step 6 ..step 100 Say v8 notices 95 other things to do (in the event loop), it starts executing them one by one. At some point b/w step 3 and step 100, returns result & asks to run dbConnection.writes callback. This event goes to the back of the queue as step 101
Node.js Programming
How can I better organize my code?
Classes & CommonJS module
22
JavaScript Classes (util.inherits)
Node.js provides handy util.inherits function to inherit a class. - This also provides subclass.super_ to access super class functions var require(util); //import util module //Super Class function Automobile(license, model) { this.license = license; this.model = model; } Automobile.prototype.getModel = function() { return model; } //Sub class function Car(license, model) { Automobile.call(this, license, model); } util.inherits(Car, Automobile);
23
CommonJS modules
//Automobile.js file function Automobile(license, model) { this.license = license; this.model = model; } Automobile.prototype.getModel = function() { return model; } exports.Automobile = Automobile;
Things to note: 1. Allows keeping JS code in separate files 2. Use exports.<name> to export something 1. Use require(path/to/module) to import it 2. use require(module).<name> to access things inside module
//Car.js file var util = require('util'); var module = require('./Automobile'); var Automobile = module.Automobile;
function Car(license, model) { Automobile.call(this, license, model); } util.inherits(Car, Automobile); console.log(new Car("1232", "BMW").model); //prints BMW
24
CommonJS modules: Exporting multiple things
//myModule.js file exports.myFunction = function () { return hi there; } exports.myArray = [foo, bar]; exports.myVariable = Im a variable;
Things to note: 1. You can directly export function, arrays, variables 2. You can export multiple things from one file using exports
//app.js file var myModule = require('./myModule'); console.log(myModule.myFunction()); //prints hi there console.log(myModule.myArray[1]); //prints bar console.log(myModule.myVariable); //prints Im a variable
25
CommonJS modules: exports v/s module.exports
//myModule.js file module.exports = function () { return hi there; }
Things to note: If you want to export only one class/function.. so that it can be used directly by the recipient, you can use: module.exports = <something>; Warning: If you use both module.exports and exports.bla, exports.bla will NOT be exported(ignored)
//app.js file var myFunction = require('./myModule'); console.log(myModule.myFunction()); //prints hi there
26
Installing external modules npm (Node Package Manager)
Use npm (Node Package Manager) to install modules npm install <moduleName> e.x. npm install express Modules are copied into ./node_modules folder /myapp /myapp/node_modules/express
Things to note: 1. npm = Node Package Manager 2. It is a CLI to install modules from http://search.npmjs.org 3. LOCAL: npm install express 1. It installs in myapp/node_modules/express 4. GLOBAL: npm install express -g 1. It installs in /usr/local/lib/node_modules/ (default) 2. Installs executable files in /usr/local/.bin (default) 5. Use GLOBAL when the library has some shell script & want to reuse it for different apps
27
package.json Describe app & dependencies in a file
//package.json { "name": MyApp", "description": My awesome twitter app", "version": "2.5.8", "author": Raja <
[email protected]>", "dependencies": { "express": 2.3.4, "mime": "", "connect-redis": ">= 0.0.1" } }
Things to note: 1. If you use package.json, you can simply do: npm install (w/o any module names) 1. Keep package.json in root directory
2. Using package.json is preferred over individual npm install <module>
1. You need to have all the modules pre-installed (i.e. npm install) before uploading your app to Cloud Foundry
28
Node.js EventEmitter (A utility class that allows emitting events)
EventEmitter class implements Observer pattern and provides on and emit APIs - It is used when creating (not using) an async library.
Node.js EventEmitter
29
Events Node.js EventEmitter
(A node.js utility class that allows emitting events)
//Simplified EventEmitter (Observer pattern) function EventEmitter() { //store events and callbacks like {event1: [callback1, callback2] , event2 : [cb3, cb4]} this.eventNameAndCallbackList = {}; } //Allow others to add a callback(function) for a event name(string) EventEmitter.prototype.on = function(eventName, callback) { //add eventName and callback to eventNameAndCallbackList }; //When an event is emitted, call each callbacks in a loop EventEmitter.prototype.emit = function(eventName) { for(var i =0; i < currentCallbacks.length ; i++) { currentCallbacks[i](); //call each callback } }; exports.EventEmitter = EventEmitter;
30
Events Node.js EventEmitter (continued)
Say you are writing an I/O library & writing readFromDB function but dont know how to handle async DB result. You can solve it by.. 1. Inheriting your class from EventEmitter 2. Then you can use its emit function to an event when data arrives (asynchronously) 3. You ask people wholl be using your library to implement on function
//myIOModule.js var util = require('util'); var events = require('events'); //myIOClass is a subclass of events.EventEmitter class var MyIOClass = function () { events.EventEmitter.call(this); }; util.inherits(MyIOClass, events.EventEmitter); MyIOClass.prototype.readFromDB = function(query){ // <--reads data code here --> this.emit('data', "some data"); } exports.MyIOClass = MyIOClass; //export the class
31
Events Node.js EventEmitter (continued)
Say you are an end-user trying to use DB library to read result from DB.. 1. Youll have to implement on function for the given event name (data) and set a callback 2. DB libraries internal function will call your callback when the result comes back
//app.js var myIOModule = require('./myIOModule'); var myIOClass = new myIOModule.MyIOClass(); myIOClass.on('data', function (data) { console.log(data); }); myIOClass.readFromDB('select * from users');
32
Events A library can emit multiple events
I/O libraries usually emit multiple events.. connected, disconnected, error, ready, data, result etc. //So you can listen to all of them..
function myFunction() { db.on(error, function(e) { console.error(e); });
db.on(connect, function() { //db is connected db.query(user); }); db.on(disconnect, function(){ console.log(db disconnected); });
db.connect(127.0.0.1, 100);
}
33
Events Error/Exception handling
//Say there was an exception trying to connect to db. Function () { try { db.connect(127.0.0.1, 4000); // failed to connect; connectionException } catch (e) { console.error(e); } }
Above try/catch wont handle it because the act of connection itself is an i/o
//Say there was an exception trying to connect to db. Function () { //Typically I/O libraries triggers error event (or callback). Well need to listen to that event db.on(error, function(e) { console.error(e); }); db.connect(127.0.0.1, 100); // failed to connect; connectionException }
34
ExpressJS
35
Hello World App using ExpressJS
var host = process.env.VCAP_APP_HOST || 'localhost'; var port = process.env.VCAP_APP_PORT || '3000';
var express = require('express'); var app = express.createServer();
Things to note:
1. ExpressJS is Ruby Sinatra inspired web framework 2. It is built on top of Connect which itself is a wrapper for http-module 3. It provides support for: 1. Dev/Prod Configurations 2. Routes 3. Templating 4. Sessions 5. Many, many other features
app.listen(port, host);
36
Hello World App using ExpressJS (Middlewares)
var express = require('express'); var app = express.createServer();
//Middlewares app.use(express.logger()); //logs requests app.use(express.static(__dirname + /public)); //sets location of public files app.use(express.bodyParser()); //parses HTTP POST body
Things to Note: 1. Middlewares are functions that helps in common tasks involved building in web applications 2. They are actually connect-module functions but exposed by ExpressJS for simplicity
37
Hello World App using ExpressJS (Environments)
var express = require('express'); var app = express.createServer();
app.configure('development', function() { //On error, print exceptions to console & to the web-page itself app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); });
app.configure('production', function() { //On error, this simply says Internal error Occurred app.use(express.errorHandler({ dumpExceptions: true, showStack: false })); app.use(express.logger()); //logs requests });
Things to Note: 1. Express uses NODE_ENV environment variable to set working environment 2. On CF, to toggle b/w development and production, you can use.. vmc env-add <appName> NODE_ENV production
38
Hello World App using ExpressJS (Routing)
var express = require('express'); var app = express.createServer(); app.use(express.bodyParser());
//Receive HTTP GET app.get('/user', function(req, res) { //Dont let people call to /user throw new Error(Im private. Call me w/ a user id"); }); app.get('/user/:id', function(req, res){ res.send('user ' + req.params.id); }); //Receive HTTP POST app.post(/register, function(req, res) { //(Use bodyParser middleware for this) var body = req.body; db.save(body.user, body.password); }
Things to note:
1. You can use Routing to listen to requests to call different functions 2. You can listen to HTTP POST, PUT etc.
39
Hello World App using ExpressJS (Sessions)
var express = require('express'); var app = express.createServer();
//Middlewares app.use(express.static(__dirname + /public)); //sets location of public files app.use(express.bodyParser()); //parses HTTP POST body app.use(express.cookieParser()); //Parses cookies headers app.use(express.session({secret: 'your secret here}));
Things to note:
1. To create sessions, use cookieParser & session middlewares 2. By default Express uses MemoryStore to store sessions
3. You can use Redis to store sessions
40
ExpressJS (Sticky sessions for multi instances)
var express = require('express'); var app = express.createServer();
//Middlewares app.use(express.static(__dirname + /public)); //sets location of public files app.use(express.bodyParser()); //parses HTTP POST body app.use(express.cookieParser()); //Parses cookies headers app.use(express.session({secret: 'your secret here, key: jsessionid }));
Things to note:
1. Sticky Session is a reverse proxy / load balancer feature to help persistent connection 2. When Sticky Session is on, request goes from Nginx to the same instance no matter how many instances of your app is running . 3. Cloud Foundrys Nginx provides Sticky Sessions on jsessionid cookie
4. W/o setting this requests are randomly sent to different instances & youll have to use external store like Redis to fetch session data (recommended).
41
ExpressJS (demo)
42
ExpressJS demo app screenshots
(routing, sessions & sticky sessions)
Demo Explains how session, sticky sessions, routing etc. works
For more: https://github.com/rajaraodv/express1
43
Socket.io
Socket.io
44
Socket.io (server side)
var sio = require('socket.io'); var express = require('express'); var app = express.createServer(); var io = sio.listen(app);//listen to express io.configure(function() { io.set('log level', 1); io.set("transports", ["xhr-polling"]); //Currently CF doesnt support websockets });
Things to Note: 1. Socket.io is mainly used to build real-time apps 2. Socket.io provides a single interface to switch b/w various transport techniques like xhrpolling, websocket, JSONP etc In addition, it provides heartbeats, reconnection, timeouts etc. that are vital for real-time apps. It works seamlessly with ExpressJS
3. 4.
45
Socket.io (server side continued)
//After listening to express..wait for connection from browser io.sockets.on('connection', function(socket) { // When the client/browser emits 'sendchat', this listens and executes socket.on('sendchat', function(data) { // We will echo it back to ALL sockets io.sockets.emit('updatechat, data); }); });
46
Socket.io (client side)
<script src="/socket.io/socket.io.js"></script>//socket.io serves this file from server var socket = io.connect(document.location.href); //connect to the server // on connection socket.on('connect', function() { console.log("client connected"); });
// Whenever the server emits 'updatechat', this updates the chat body socket.on('updatechat', function (data) { $('#conversation').append(data); // append it to my list });
//When the user enter some data, send it to server function sendchat() { var message = $('#chatField').val(); // Emit or tell server to execute 'sendchat socket.emit('sendchat', message); }
47
Socket.io (+ ExpressJS) Demo app screenshots
For more: https://github.com/rajaraodv/socketio1
48
Questions?
Questions?
@rajaraodv (github.com/rajaraodv) @cloudfoundry (github.com/cloudfoundry)
49