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.

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.

      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);
});

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.

      
// fileutils.js

// 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 zlib = require('zlib');
  var fileStream = fs.createReadStream(filename);
  var gzip = zlib.createGzip();
  return fileStream.pipe(gzip);
};


organizing code in modules

The require function is used to consume modules.

      
// main.js

var fileUtils = require('./fileUtils');
var indexStream = fileUtils.gzipFileStream(__dirname + '/static/index.html');
indexStream.pipe(response);
    


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.


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(){ ... }
], callback);        
        

performance - Streams

  • Use streams - read large data/files in chunks (or line by line)
  • Reading  a file line by line using stream and readline modules:
  var readline = require('readline');
  var fs = require('fs');
  var stream = require('stream');

  var instream = fs.createReadStream('some/file/path.txt');
  var outstream = new stream;
  var rl = readline.createInterface(instream, outstream);

  rl.on('line', function (line) {
    consle.info('got line...', line);
    // do something with that line..
  });

  rl.on('close', function () {
    // do something on finish here
  }); 

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'))
  • fs.readFileSync(filePath).toString('base64')

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.


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

Copy of Copy of node.js

By Ami Turgman

Copy of Copy of node.js

A node.js intro course

  • 1,252