Node.js 4.X

JaxNode November 2015

Upcoming Events

  • Lastcall JSCONF

Survey

A little History

Node Development

  • Invented by Ryan Dahl,
  • Opensource BDFL
  • Joyent sponsored project
  • Isaac Schlueter took over from Dahl in 2012
  • T.J. Fontaine took over from Schlueter in 2014
  • Core committers became upset with rate of change
  • Fedor Indutny forked Node in November 2014
  • New linux style foundation created for Node
  • September merged version released

Key issues

  • Pace of development
  • V8 version was really old
  • Pull requests were not being merged

Release Plan

  • Major version twice a year
  • Include new version of V8
  • Google releases a new version of V8 every 6 weeks,
  • node will only get a new version every 6 months

Node.js 4 enhancements

  • New language features
  • Speed improvements
  • Better Memory usage

Native Modules

  • V8 engine went from 3.26 to 4.5
  • Many native modules broke
  • Rod Vagg added NAN interface (Yes, he was trolling)
  • Native Abstractions for Node
  • C++ interface to prevent breaking of native modules

ES2015

  • Most features of ES6
  • Rolled into ES2015
  • Some features released in 2016
  • Features not supported in Node can be done using Babel or TypeScript

ES2015 Features in Node 4

Let and Const

Iterators and Generators

Arrow => functions

Reflection

New literals

Template Strings

Classes

Lexical Scoping

Maps, Set, WeakMap

ArrayBuffer

Promises

Octal support

Class

  • class keyword added
  • similar to classes in Java, C#
  • constructor method
  • extends keyword to inherit from other classes
"use strict";

class MeetupGroup {
	constructor(name) {
		this.name = name;
	}
	
	Say() {
		// Notice use of string templates.
		console.log(`This the ${this.name} meetup group!`);
	}
}

class JavaScriptGroup extends MeetupGroup {
	Say() {
		super.Say()
		console.log('And is a JavaScript User Group.');
	}
}

let meetup = new MeetupGroup('JaxNode');

meetup.Say();
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var MeetupGroup = (function () {
    function MeetupGroup(name) {
        this.name = name;
    }
    MeetupGroup.prototype.Say = function () {
        console.log("This the " + this.name + " meetup group!");
    };
    return MeetupGroup;
})();
var JavaScriptGroup = (function (_super) {
    __extends(JavaScriptGroup, _super);
    function JavaScriptGroup() {
        _super.apply(this, arguments);
    }
    JavaScriptGroup.prototype.Say = function () {
        _super.prototype.Say.call(this);
        console.log('And is a JavaScript User Group.');
    };
    return JavaScriptGroup;
})(MeetupGroup);
var meetup = new MeetupGroup('JaxNode');
meetup.Say();

for-of Syntax

  • similar to foreach in C#
  • iterates over the item instead of index
  • excludes properties, bug in for-in
"use strict";

let arr = [3, 5, 7];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // logs "0", "1", "2", "foo"
}

for (let i of arr) {
   console.log(i); // logs "3", "5", "7"
}

arr.forEach(item => {
	console.log(item);
});

Let keyword

  • different than Let in F# or Swift
  • is mutable
  • better than var
  • protects block scope
"use strict";

varTest();
letTest();

function varTest() {
  var x = 31;
  if (true) {
    var x = 71;  // same variable!
    console.log(x);  // 71
  }
  console.log(x);  // 71
}

function letTest() {
  let x = 31;
  if (true) {
    let x = 71;  // different variable
    console.log(x);  // 71
  }
  console.log(x);  // 31
}

Const

  • creates immutable variables
  • similar to Let in F# and Swift
const bar = 'Immutable';
console.log(bar);
bar = 'mutable'; // Will not throw an error unless you use use strict, but will keep original value.
console.log(bar);

Sets and WeakSets

  • Set is a collection
  • Built in methods for add(), has(), delete() and clear()
  • entries() will return an *generator
  • WeakSet is for objects only, no primatives
  • WeakSet allows for proper garbage collection
var mySet = new WeakSet();
var c1 = { foo: "bar" };
var c2 = {};
var c3 = {};

mySet.add(c1);
mySet.add(c2);

console.log(mySet.has(c2)); // true
console.log(mySet.has(c3));    // false, foo has not been added to the set

mySet.delete(c2); // removes window from the set
console.log(mySet.has(c2));    // false, window has been removed

Maps and WeakMaps

  • Like a HashMap or Dictionary
  • Contains collection of key/vales pairs
  • Methods include add(), has(), get() and delete()
  • WeakMaps for objects and GC
var myMap = new WeakMap();
var a1 = {};
var b1 = {};

myMap.set(a1, 'foo');

console.log(myMap.get(a1));

console.log(myMap.has(a1));
console.log(myMap.has(b1));

myMap.delete(a1);
console.log(myMap.has(a1));

Generators

  • Generates an iteratable protocol
  • Great for Async like functionality
  • Denoted by * in front of function name
  • uses the yield keyword to return value
  • return type is a tuple with value and done bool
"use strict";

function *getSomeValues() {
	yield 1;
	yield 2;
	yield 3;
	yield 4;
	yield 5;
}

var someValues = getSomeValues();

console.log(someValues.next()); // returns { value: 1, done: false }
console.log(someValues.next()); // returns { value: 2, done: false }
console.log(someValues.next()); // returns { value: 3, done: false }
console.log(someValues.next()); // returns { value: 4, done: false }
console.log(someValues.next()); // returns { value: 5, done: false }
console.log(someValues.next()); // returns { value: undefined, done: true }

Promises

  • Helps make callback code look cleaner
  • var p = new Promise(executor);
  • var executor = function(resolve, reject) {...}
  • p.then((obj) => {...}).error((err) => {...}).catch((ex) => {...});
  • Q and Bluebird libraries simplify creation of Promises
"use strict";
// Without promises
var fs = require('fs'),
    rootPath = 'C:\\Users\\dfekke\\Documents\\',
    ext = 'tiff',
    newExt = 'TIF';

fs.readdir(rootPath, 
    function(err, files) {
        if (err) {
            console.error("unable to read directory");
        } else {
            var re = new RegExp("^.*\\." + ext + "$");
            for (var file in files) {
                if (re.test(files[file])) {
                    console.log(files[file]);
                    var oldPath = rootPath + files[file];
                    var newPath = rootPath + files[file].substring(0, files[file].length - ext.length) + newExt;
                    console.log(newPath);
                    fs.rename(oldPath, 
                                newPath, 
                                function (err) {
                                    console.error("unable to rename file");
                    }); 
                }
            }   
        }
});
"use strict";
// With promises
var fs = require('fs'),
	Promise = require("bluebird"),
	rootPath = 'C:\\Users\\dfekke\\Documents\\',
	ext = 'tiff',
	newExt = 'TIF';

Promise.promisifyAll(fs);

fs.readdirAsync(rootPath).then((files) => {
	var re = new RegExp("^.*\\." + ext + "$");
	files.forEach(file => {
		if (re.test(file)) {
			console.log(file);
			var oldPath = rootPath + file;
			var newPath = rootPath + file.substring(0, file.length - ext.length) + newExt;
			console.log(newPath);
			fs.renameAsync(oldPath, newPath).catch(err => {
				console.error("unable to rename file");
			});
		}
	});
}).catch((err) => {
	console.error("unable to read directory");
});

Lexical scope

  • => functions preserve lexical scope of 'this'
  • eliminate var that = this; code
  • useful in callback code
"use strict";

let printName = name => console.log(`Your user group name is ${name}`); 

printName('JaxNode');

// Lexical this from Babel documentation.
var bob = {
  _name: "Bob",
  _friends: ['Tommy', 'Richard', 'Susan'],
  printFriends1() {
    // Here we hoist the this object into that so we can use it in the closure function.
    var that = this;
    this._friends.forEach(function (friend, index){
		console.log(`${that._name}  knows  ${friend}`);	
	});
  },
  printFriends2() {
	// Here there is no need to hoist the this object because it can be scoped in the lambda.
    this._friends.forEach(f =>
      console.log(`${this._name}  knows  ${f}`));
  }
};

bob.printFriends1();
bob.printFriends2();

Node v5.0

  • V8 engine 4.6
  • Includes ...spread operator
  • adds new.target property
"use strict";
//Available in Node 5.0

// Merging arrays

// Code with spread operator
let inner = [3, 4];
let merged = [0, 1, 2, ...inner, 5]; //Spread operator will fail if run in Node 4.X

console.log(merged);

function Foo() {
  if (!new.target) throw "Foo() must be called with new";
  console.log("Foo instantiated with new");
}

Foo(); // throws "Foo() must be called with new"
new Foo(); // logs "Foo instantiated with new"

ES2016 features

  • Async and Await
  • Types, think TypeScript

Questions?

Slides and Examples

  • jaxnode.github.io/node4es2015/
  • slides.com/davidfekke/node_4
  • github/davidfekke/node4es2015

Contact Me

  • David Fekke
  • david fekke at gmail dot com
  • Skype: davidfekke
  • Twitter: @jaxnode and @davidfekke
  • github.com/davidfekke