Intro to

Node.js

Chris Cowan

Twitter: @uhduh

Github: ccowan


The GOAL of NODE.JS IS TO provide an easy way to build scaleable network programs



NODE.JS IS NOT ANOTHER WEB FRAMEWORK

NODE.JS IS:

A Web Server
TCP Server
Awesome Robot Server
Drone Controller
Command Line Application
Proxy Server
Steaming Server
VoiceMail Server
Music Machine
(any thing that has to deal with I/0)

NODE.JS IS



NODE.JS is 

FUN!

WHY NODE.JS?

Non-Blocking I/O
Based On Chrome's V8 Engine
20,000+ Modules
Very Active Community
Supported on Mac, Linux, and Windows
One Language to Rule them All
JavaScript is the Language of the Web

Mostly True Facts

About Node.jS

9 out of 10 Web Developers prefer to use Node.js

It increases employee satisfaction by 99.99999% 

Every 2 minutes a developer decides to rewrite their PHP site with Node.js

94.7% of Hackathons are won using 
Node.js and Socket.io.

Basic Example

Create helloworld.js with:
console.log('Hello World');
On the command line run
node helloworld.js
You should see
Hello World

Basic HTTP SERVER


var http = require('http');
 
var server = http.createServer(function (req, res) {
  res.writeHead(200);
  res.end('Hello World');
});
 
server.listen(4000);

* Running this script on my development box I can achieve 10,000+ requests per second with 100 concurrent connections without breaking a sweat.


What is 

Non-Blocking IO?

AND WHY SHOULD I CARE?

BLOCKING I/0

// Get Users - 20ms
$query = 'SELECT * FROM users WHERE id = ?';
$users = query($query, array($_GET['id']));
print_r($users);

// Get Activities - 130ms
$query = 'SELECT * FROM activities WHERE user_id = ? ORDER BY TIMESTAMP LIMIT 50';
$activities = query($query, array($_GET['id']));
print_r($activities);

// Get Leader Board - 120ms
$query = 'SELECT count(points),user_id FROM activities GROUP BY user_id LIMIT 50';
$leader_board = query($query);
print_r($leader_board);
270ms = SUM($user, $activities, $leader_board)

NON-BLOCKING I/0

// Get Users - 20ms
var query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [req.query.id], function (err, users) {
    console.log(users);
});

// Get Activities - 130ms
query = 'SELECT * FROM activities WHERE user_id = ? ORDER BY TIMESTAMP LIMIT 50';
db.query(query, [req.query.id], function (err, activities) {
    console.log(activities);
});

// Get Leader Board - 120ms
query = 'SELECT count(points),user_id FROM activities GROUP BY user_id LIMIT 50';
db.query(query, function (err, leader_board) {
    console.log(leader_board);
});
130ms = SUM(user, activities, leader_board)



ReAL WORLD EXAMPLE

of Why Non-Blocking I/O Matters


10 Separate Data Calls!


THE MOST JARRING THING ABOUT SERVER SIDE JAVASCRIPT IS THINKING IN CALLBACKS

The NODE.JS CALLBACK PATTERN

awesomeFunction(args, function (err, data) {
    if (err) {
        // Handle Error
    }
    
    // Do something awesome with the data
});
  • Error First then success... ALWAYS!
  • Because this is the defacto standard, 99.99999% of the time you will be able to guess how a Node.js module works


Some people will say

Callbacks are the devil'S WORK

db.query(userQuery, [id], function (err, userResults) {
    db.query(activityQuery, [id], function (err, activityResults) {
        db.query(leaderBoardQuery, function (err, leaderBoardResults) {
            // I HATE MY LIFE!
        });
    });
});
One of the biggest mistakes is to get yourself in to CALLBACK HELL by nesting callbacks inside of callbacks inside of callbacks inside of callbacks inside of callbacks... aaahhhrrigh!

AVOIDING CALLBACK HELL


Keep your code shallow

Break up  your code into small chunks

Use a sequential library like async

Async Module Example

var async = require('async');
var db    = require(’db');
 
function getUser (callback) {
  var query = 'SELECT * FROM users WHERE id = ?';
  db.query(query, [userId], callback);
}
 
function getActivities (callback) {
  var query = 'SELECT * FROM activities ORDER BY timestamp LIMIT 50';
  db.query(query, callback);
}
 
function getLeaderBoard (callback) {
  var query = 'SELECT count(points) as total, user_id FROM activities LIMIT 50';
  db.query(query, callback);
}
 
var tasks = [getUser, getActivities, getLeaderBoard];
async.parallel(tasks, function (err, results) {
  var user        = results[0][0];
  var activities  = results[1];
  var leaderBoard = results[2];
});

The Node PAckage manager

otherwise known as NPM!

NPM is how you harness the awesomeness of the Node.js community

USING NPM

It's standard practice to install modules locally for  your current project. Modules are installed in   ./node-modules in the current directory
To install a new module: 
npm install <module>
To find a module in the repo: 
npm find <module>
To list the modules (and depedancies) for the curent project: 
npm list

Basic Module Example

var currentCount = 0;

module.exports.incr = function () {
    return ++currentCount;
};
Once you've created a module in counter.js you use it like this...
var counter = require('./counter');
counter.incr();
var count = counter.inrc();

Keep this in mind... modules are loaded once and cached. So when you load the module a second time in your app, require just returns the cached module object. This lets you do interesting things...

CREATING YOU OWN MODULES


require('./example') will load either example.js or example/index.js or the entry point defined in package.json

Run npm init to bootstrap  your new module, this will create the package.json

Try to stick to creating "Pure JavaScript" module if possible. It will give you less headaches down the road

INSTALLING YOUR MODULES

Run npm link in the module directory. Then run 
npm link module in the project directory.

Add the module's Gitub URL to your package.json dependancies and run npm install.
"dependencies": {
    "my-module": "https://github.com/my-name/my-module/tarball/master"
}
Link the module by hand to your projects node_modules directory


OPRAH's Favorite Modules

request async node-dev hogan.js connect underscore restify moment schemajs grunt coffee-script mysql mocha redis less



Questions?

Twitter: @uhduh

introtonodejs

By ccowan

introtonodejs

  • 3,939