node.js

An intro to node.js

http://nodejs.org

What is node.JS

A server side JavaScript engine written by Ryan Dahl


  - Enjoys the fruits of the browsers war.
     Fast JavaScript VMs and JIT. Faster than the Ruby VM or

     the Python interpreter

  - Well suited for high I/O scenarios 
     web like request/response, reading files, network streams, or
     streams in general
  - Designed with async in mind and non blocking I/O
  - Active community generating tens of thousands
     extension modules




Node’s Goal is to provide an easy way to build scalable network programs




On the device node enables writing light web like services efficiently and quickly

Why node.js

- Non blocking I/O

- Code can be shared between the client and the server

- 60,000+ extension modules

- Cross platform and supported by Microsoft


Our team increased its coding velocity by x10 fold


Hello Node

var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Node!\n'); }).listen(1337);

console.log('Server running at http://127.0.0.1:1337/');


The most basic http server implementation.

organizing code in modules

Node uses the CommonJS approach for organizing code.
The developer can create extension units called modules for code reuse, maintainability and testing.

      
// file utils

// initilization code goes here

var moduleWideVariable = 'This can only be accessed by the module members';

// the exports object will be the one being returned by the require function
exports.gzipFileStream = function(filename) {
  // lazy loading the actual needed modules
  var fs = require('fs');
  var zlip = require('zlib');
  var fileStream = fs.createReadStream(filename);
  var gzip = zlib.createGzip();
  return fileStream.pipe(gzip);
};


ORGANIZING CODE IN MODULES

  • Modules are loaded using the global require method (specific to node.js)
  • The require method accepts a name of a module, and returns a JavaScript object representing the module.
  • It accepts both a full file path, as well as a folder that contains a package.json file.
  • 2 types of modules:
    • JavaScript
    • Native bindings written in c++ (it's just a DLL with a ".node" extension)

ORGANIZING CODE IN MODULES

Consuming modules is easy:

      
// fs is a builtin module
var fs = require('fs');
// fs has a readFileSync function
var data = fs.readFileSync('./data.txt');

// request is an external module
var request = require('request');
// it's actually a function, so we can just call it in order to make a request
request('http://www.bing.com', function(err, res, body) {
 // ...
});

ORGANIZING CODE IN MODULES

  Authoring modules is easy as well:

exports.helloWorld = function {
  return 'hello world!';
};

Everything you'll set on the exports object will be exposed to the user of the module.

You can even replace exports with another object (like in request), by setting the module.exports field.

Other than module, and exports, each module also has a built in __filename and __dirname variables.

DEMO


ORGANIZING CODE IN MODULES

  Node.js has a bunch of built in modules.

exports.helloWorld = function {
  return 'hello world!';
};

Everything you'll set on the exports object will be exposed to the user of the module.

You can even replace exports with another object (like in request), by setting the module.exports field.

Other than module, and exports, each module also has a built in __filename and __dirname variables.

DEMO

node_modules folder

If the module identifier passed to require() is not a native module, and does not begin with  '/',  '../', or './', then node starts at the parent directory of the current module, and adds  /node_modules, and attempts to load the module from that location.

   

If it is not found there, then it moves to the parent directory, and so on, until the root of the tree is reached.


if not found, it will look for a NODE_PATH environment variable.


Event emitters

Many of the built in constructs in node inherit from the EventEmitter class. This allows developers to register handlers for events in the life of the different objects.

For example a request object.

      var http = require('http');
      
      var req = http.get('http://www.bing.com', function(err, res) {
        res.on('data', function(data) {
          console.log(data);
        });
        
        res.on('error', function(err) {
          console.error('Error in response stream', err);
        });
        
        res.on('end', function() {
          console.log('DONE FETCHING bing.com');
        });
      });
      
      req.end();
      
  

Streams

Node supports the notion of streams for abstracting efficient non-blocking access to system resources. Files, Network, Pipes, Crypto are a few examples which node abstracts as streams.

This allows for a powerful chaining syntax that provides the developer with a concise clear code that is highly efficient.

      
var fs = require('fs');
var zlib = require('zlib');
var http = require('http');

http.createServer(function(req, res) {
  var fileStream = fs.createReadStream(__dirname + '/static/index.html');
  var gzip = zlib.createGzip();
  res.writeHead((200, { 
    'Content-Type': 'text/html',
    'Content-Encoding': 'gzip',
  });
  
  // pipe the file into the gzip stream and right into the response stream
  // using efficient non-blocking I/O

  fileStream.pipe(gzip).pipe(res);
});
      
  


NPM - Node Package Manager

installing packages

mkdir node_modules

npm install async


For DSS we created an internal NPM site http://dss
All the modules appearing in the internal site have been LCA approved or developed by internal Microsoft teams.


Feel free to add internal modules to the internal site. If you need additional open source modules from the public site please let us know and we will run them through LCA and add them to the internal site.


Popular modules

ExpressJS - Web framework

var express = require('express');
var app = express();

app.use(express.bodyParser());

app.get('/hello.txt', function(req, res){
  res.send('Hello World');
});

var server = app.listen(3000, function() {
    console.log('Listening on port %d', server.address().port);
});


In DSS we use a lightweight module called middler that offers similar basic functionality.


Async - Flow Control

async.map(['file1','file2','file3'], fs.stat, function(err, results){
    // results is now an array of stats for each file
});

async.filter(['file1','file2','file3'], fs.exists, function(results){
    // results now equals an array of the existing files
});

async.parallel([
    function(){ ... },
    function(){ ... }
], callback);

async.series([
    function(){ ... },
    function(){ ... }
]);        
        

PeRFORMANCE - Buffer

  • Use node's built-in Buffer to hold chunks of data
  • Efficient: Buffer uses a pool for small sized buffers (< 8k), and for larger buffers, memory is actually allocated by native code (and not JS), making things much more efficient
  • Built-in supports for different encodings
  • Could be directly accessed using indexes
  • // create a new buffer from string, encode as utf8
    var buffer = new Buffer("I'm a string!", "utf-8")
    // print the length of the buffer:
    console.info(buffer.length)
    // now, get the first byte:
    console.log(buffer[0])
    // you can even convert to base64!
    console.info(buffer.toString('base64'))

performance - Streams

  • Use streams - to read large data/files in chunks

  • But....memory-wise , reading large bulks of data could be more efficient than reading smaller bulks since the memory allocations are more continuous.

Performance -Memory MGMT

  • Don't hold anything on the global object unless you have to
  • Remember to use the var keyword:
  • // j is undefined here
    function func {
      // good, will hold the var in the scope of func
      var i = 10;
      // bad, j is now actually hung on the global
      j = 10;
    }
    
    func();
    // i is undefined here, and j=10 here!

PERFORMANCE - MORE Memory MGMT

  • Call CollectGarbage() when necessary to explicitly call the garbage collector to free up memory.
    (specific to node.ch/dss. node.js (with v8) has the gc() function  when  invoked with --expose-gc  switch)

  • Can be called after large chunks of data were introduced into JS in order to free up memory faster

Copy of node.js

By Nadav Bar

Copy of node.js

A node.js intro course

  • 1,485