Вы находитесь на странице: 1из 49

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 <rajar@vmware.com>", "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

Вам также может понравиться