State of Node

State of Node

Entwicklungsgeschichte der Node.js Plattform. Kurzer Überblick über die aktuell unterstützten Features. Entwicklungsmuster für asynchrone Operationen wie Promises, Streams und RxJS

9fd17a38660f0c98089a65c0a7da65d1?s=128

Sebastian Springer

June 20, 2016
Tweet

Transcript

  1. State of

  2. Sebastian • Sebastian Springer • aus München • arbeite bei

    MaibornWolff GmbH • https://github.com/sspringer82 • @basti_springer • JavaScript Entwickler
  3. IT-Beratung & Software Engineering

  4. None
  5. Wie alles begann https://www.youtube.com/watch?v=L_JKb61EalQ https://de.wikipedia.org/wiki/S%C3%BCdamerika#/media/File:South_America_satellite_orthographic.jpg Tim Reckmann / pixelio.de

  6. 2009 Jörg Sabel / pixelio.de $ node --version v0.1.0

  7. Der Kern Tim Reckmann / pixelio.de libeio libev V8-Engine DNS

    Crypto zlib
  8. Kern Kern Node.js Kern Bindings Library Applikation Applikation

  9. Node.js Node.js

  10. 2011 libuv Node.js libuv libev libeio IOCP $ node --version

    v0.6.0
  11. 2014 - Der Fork $ node --version v0.12.x 1.0 …

    2.0 … 0.12
  12. 2015 - Der Merge $ node --version v4.0.0

  13. Die Änderungen Long Term Support Steering Commitee

  14. ECMAScript 2015

  15. Klassen Manfred Jahreis / pixelio.de

  16. Class Dienen zur besseren Strukturierung von Applikationen Syntactical Sugar, um

    das Prototypen-Konzept von JavaScript. Sie werden mittlerweile nativ von Node.js unterstützt.
  17. Class class Task {
 
 constructor(title) {
 this.title = title;


    this.state = 'todo';
 }
 
 complete() {
 this.state = 'done';
 }
 
 }
  18. 'use strict';
 
 var EventEmitter = require('events');
 
 class Greeter

    extends EventEmitter {
 
 greet() {
 this.emit('greeting', 'Hello World');
 }
 
 }
 
 var greeter = new Greeter();
 greeter.on('greeting', function (e) {
 console.log(e);
 });
 greeter.greet();
  19. Arrow Functions Jürgen Hüsmert / pixelio.de

  20. Arrow Functions class List {
 
 constructor(tasks) {
 this.tasks =

    tasks;
 }
 
 getDone() {
 return this.tasks
 .filter(task => task.state === 'done');
 }
 
 }
  21. Arrow Functions var myObj = {
 data: false,
 init: function()

    {
 event.on('data',
 function() {
 this.data = true;
 }
 );
 }
 };
 
 myObj.init();
  22. Arrow Functions var myObj = {
 data: false,
 init: function()

    {
 eventBus.on('data', () => {
 this.data = true;
 });
 }
 };
 
 myObj.init();
  23. Arrow Functions Sind an den Kontext ihrer Definition gebunden.

  24. Destructuring Rahel Szielis / pixelio.de

  25. Destructuring Strukturen in einzelne Variablen zerlegen

  26. Destructuring var person = {name: 'Klaus', age: 42};
 var {name,

    age} = person; var arr = [1, 2, 3];
 var [one, two, three] = arr; var person = {name: 'Klaus', age: 42};
 var {name: firstname, age} = person;
  27. Scoping Peter Smola / pixelio.de

  28. Scoping Global: Variablen sind überall verfügbar. Function: Variablen sind in

    der aktuellen Funktion und allen Subroutinen verfügbar. Closure: Erstellender Kontext einer Funktion und die Funktion selbst
  29. let Variable ist nur im aktuellen Block gültig. Variablen werden

    innerhalb des Block gehoistet. for (let task in tasks) {
 console.log(task);
 }
  30. const Nicht veränderliche Werte const pi = 3.14;

  31. Rest

  32. Rest arguments ist böse! arguments ist kein richtiges Array-Objekt Rest

    Parameter steht für eine beliebige Anzahl von Argumenten. Argumentenliste wird in ein Array umgewandelt.
  33. Rest function sayHello(...args) {
 console.log('Number of arguments: ' + args.length);


    }
 sayHello('Hallo', 'München');
  34. Spread CFalk / pixelio.de

  35. Spread Der Spread Operator kann überall eingesetzt werden, wo ein

    Array in eine Argumentenliste umgewandelt werden soll. Verhält sich also ähnlich wie apply.
  36. Spread function sayHello(greeting, name) {
 console.log(`${greeting} ${name}`);
 }
 var args

    = ['Servus', 'München'];
 sayHello.apply(null, args);
  37. Spread function sayHello(greeting, name) {
 console.log(`${greeting} ${name}`);
 }
 var args

    = ['Servus', 'München'];
 sayHello(...args);
  38. Promises Lupo / pixelio.de

  39. Promises Versprechen auf die Erledigung einer asynchronen Aufgabe. Events? Gut

    für Fire and Forget, nicht aber, wenn es um Erfolg/ Misserfolg geht.
  40. Promises • Fulfill: Aktion war erfolgreich. • Reject: Aktion war

    nicht erfolgreich. • Pending: Noch kein fulfill oder reject • Settled: fulfilled oder rejected
  41. Promises var promise = new Promise(function(resolve, reject) {
 if (true)

    {
 resolve("Everything is fine");
 }
 else {
 reject("Something went wrong");
 }
 });
 
 promise.then(function success(data) {
 console.log(data);
 }, function failure(err) {
 console.log(err);
 });
  42. Promises - Chaining function async() {
 return new Promise(function (res,

    rej) {
 res(1);
 });
 }
 
 async().then(function (v) {
 return v + 1;
 }).then(function (v) {
 return v + 1;
 }).then(function (v) {
 console.log(`value: ${v + 1}`);
 });
  43. Flusssteuerung - all function async(number, timeout) {
 return new Promise(function

    (resolve, reject) {
 setTimeout(function () {
 console.log(`Promise Nr. ${number} resolved`);
 resolve(number);
 }, timeout);
 });
 }
 
 Promise.all([
 async(1, 1000),
 async(2, 2000),
 async(3, 3000)
 ]).then(function (data) {
 console.log(`all promises resolved ${data}`);
 });
  44. Flusssteuerung - all P1 P2 P3 …

  45. Flusssteuerung - race function async(number, timeout) {
 return new Promise(function

    (resolve, reject) {
 setTimeout(function () {
 console.log(`Promise Nr. ${number} resolved`);
 resolve(number);
 }, timeout);
 });
 }
 
 Promise.race([
 async(1, 1000),
 async(2, 2000),
 async(3, 3000)
 ]).then(function (data) {
 console.log(`one promise resolved ${data}`);
 });
  46. Flusssteuerung - all P1 P2 P3 …

  47. Streams Paul-Georg Meister / pixelio.de

  48. Source Step Step Sink Input Output Step einfügen entfernen

  49. Streams sind EventEmitters EventEmitter Callbacks Event on(‘event’, callback) emit(‘event’ [,

    arg1][, arg2])
  50. Streams in Node.js http fs child_process tcp zlib crypto

  51. Beispiel Source: MySQL (relational DB) Step 1: Format anpassen Step

    2: Profilbilder herunterladen Sink: MongoDB (document orientated DB)
  52. Verschiedene Arten von Streams Karl-Heinz Laube / pixelio.de

  53. Stream types • Readable: Informationen lesen (Source) • Writable: Informationen

    schreiben (Sink) • Duplex: readable und writable • Transform: (Basis: Duplex) Ausgabe wird anhand der Eingabe berechnet
  54. Readable Streams Andreas Hermsdorf / pixelio.de

  55. Readable Streams in Node.js http.Client.Response fs.createReadStream process.stdin child_process.stdout

  56. ReadStream var fs = require('fs');
 
 var options = {


    encoding: 'utf8',
 highWaterMark: 2
 };
 
 var stream = fs.createReadStream('input.txt', options);
 
 var chunk = 1;
 stream.on('readable', function () {
 console.log(chunk++, stream.read());
 });
  57. ReadStream Modes • Flowing Mode: Information flows automatically and as

    fast as possible. • Paused Mode (Default): Information has to be fetched via read() manually.
  58. Flowing Mode stream.on('data', function (data) {}); stream.resume(); stream.pipe(writeStream);

  59. Paused Mode stream.pause(); stream.removeAllListeners('data');
 stream.unpipe();

  60. Events • readable: Der nächste Chunk ist verfügbar • data:

    Daten werden automatisch gelesen • end: Es gibt keine weiteren Daten mehr • close: Der Stream wurde geschlossen • error: Es ist ein Fehler aufgetreten
  61. Object Mode Normalerweise werden String- und Buffer-Objekte unterstützt. Im Object

    Mode können beliebige JS-Objekte gestreamt werden. Encoding und Chunk Size werden ignoriert.
  62. "use strict";
 var Readable = require('stream').Readable;
 
 class TemperatureReader extends

    Readable {
 constructor(opt) {
 super(opt);
 this.items = 0;
 this.maxItems = 10;
 }
 _read() {
 if (this.items++ < this.maxItems) {
 this.push({
 date: new Date(2015, 9, this.items + 1),
 temp: Math.floor(Math.random() * 1000 - 273) + '°C'
 });
 } else {
 this.push(null);
 }
 }
 }
 
 var tr = new TemperatureReader({objectMode: true});
 var tempObj;
 tr.on('readable', function() {
 while (null !== (tempObj = tr.read())) {
 console.log(JSON.stringify(tempObj));
 }
 });
  63. Writable Streams I-vista / pixelio.de

  64. Writable Streams in Node.js http.Client.Request fs.createWriteStream process.stdout child_process.stdin

  65. WriteStream var ws = require('fs')
 .createWriteStream('output.txt');
 
 for (var i

    = 0; i < 10; i++) {
 ws.write(`chunk ${i}\n`);
 }
 ws.end('DONE');
  66. Events • drain: Ist der Rückgabewert von write() false, gibt

    das drain Event an, wenn der Stream wieder Daten akzeptiert • pipe/unpipe: Wird ausgelöst, sobald ein Readable Stream in diesen Stream gepiped wird.
  67. Buffering • cork()/uncork(): Schreiboperationen werden in den Speicher gepuffert beziehungsweise

    der Speicher wird geleert.
  68. Buffering var ws = require('fs')
 .createWriteStream('output.txt');
 
 ws.write('START');
 
 ws.cork();


    
 for (var i = 0; i < 10; i++) {
 ws.write(`chunk ${i}\n`);
 }
 setTimeout(function () {
 ws.uncork();
 
 ws.end('DONE');
 }, 2000);
  69. Piping Rolf Handke / pixelio.de

  70. Piping Source Sink Input Output

  71. Piping var fs = require('fs');
 
 var read = fs.createReadStream('input.txt');


    var write = fs.createWriteStream('pipe.txt');
 
 write.on('pipe', function () {
 console.log('piped!');
 });
 
 
 read.pipe(write);
  72. WriteStream "use strict";
 
 var Writable = require('stream').Writable;
 
 class

    WriteStream extends Writable {
 _write(chunk, enc, done) {
 console.log('WRITE: ', chunk.toString());
 done();
 }
 }
 
 
 var ws = new WriteStream();
 
 for (var i = 0; i < 10; i++) {
 ws.write('Hello ' + i);
 }
 ws.end();
  73. Duplex Streams Rainer Sturm / pixelio.de

  74. Duplex Streams Duplex Streams implementieren sowohl das Readable als auch

    das Writable Interface. Duplex Streams sind die Basis für Transform Streams.
  75. Duplex Streams tcp sockets zlib streams crypto streams

  76. Duplex Streams var Duplex = require('stream').Duplex;
 
 class DuplexStream extends

    Duplex {
 _read() {
 ...
 }
 _write() {
 ...
 }
 }
  77. Transform Streams Dieter Schütz / pixelio.de

  78. Transform Streams Transform Streams transformieren eine Eingabe nach bestimmten Regeln

    in eine Ausgabe. Sie basieren auf Duplex Streams, haben aber eine wesentlich einfachere API.
  79. Transform Streams "use strict";
 
 var fs = require('fs');
 var

    read = fs.createReadStream('input.txt');
 var write = fs.createWriteStream('transform.txt');
 
 var Transform = require('stream').Transform;
 
 class ToUpperCase extends Transform {
 _transform(chunk, encoding, callback) {
 this.push(chunk.toString().toUpperCase());
 callback();
 }
 }
 
 var toUpperCase = new ToUpperCase();
 
 read.pipe(toUpperCase)
 .pipe(write);
  80. Transform Streams _flush(callback) Wird aufgerufen, sobald alle Daten konsumiert wurden.

    Wird vor dem end-Event ausgeführt.
  81. Module URSfoto / pixelio.de

  82. Module Aktuell wird die Umsetzung des ES2015 Modulsystems unter Node.js

    noch diskutiert, um einen möglichst störungsfreien Übergang zu schaffen. Eine gewisse Zeit lang sollen CommonJS-Module und ES2015-Module parallel unterstützt werden.
  83. Modulsystem - Basics export function HelloWorld() {
 
 }
 


    export var name = 'Klaus'; Der Name der Variable oder Funktion wird zum Exportnamen.
  84. Modulsystem - Basics import {helloWorld, name as firstname} from ‘./export'


    
 helloWorld();
 
 console.log(firstname);
  85. Modulesystem - Defaults export default function sayHello(name) {
 console.log(`Hello ${name}`);


    } import greeting from './export';
 
 greeting('Peter');
  86. Modulsystem import 'jquery'; // import a module without any import

    bindings
 import $ from 'jquery'; // import the default export of a module
 import { $ } from 'jquery'; // import a named export of a module
 import { $ as jQuery } from 'jquery'; // import a named export to a different name
 
 export var x = 42; // export a named variable
 export function foo() {}; // export a named function
 
 export default 42; // export the default export
 export default function foo() {}; // export the default export as a function
 
 export { encrypt }; // export an existing variable
 export { decrypt as dec }; // export a variable as a new name
 export { encrypt as en } from 'crypto'; // export an export from another module
 export * from 'crypto'; // export all exports from another module
 // (except the default export)
 import * as crypto from 'crypto'; // import an entire module instance object
  87. $ npm --version 3.0.0

  88. Neue Darstellung

  89. Der Node Package Manager ist seit der Version 0.6.3 Teil

    von Node.js. Installation, Update und Removal von Paketen. Das zentrale Repo liegt unter npmjs.org. Aktuell gibt es > 250k Pakete. Jeder kann Pakete veröffentlichen. Jedes Paket löst seine eigenen Abhängigkeiten auf.
  90. Mittlerweile löst nicht mehr jedes Paket seine Abhängigkeiten selbst in

    einem node_modules-Verzeichnis auf. Sämtliche Pakete liegen in einem node_modules- Verzeichnis. Nur bei Versionskonflikten gibt es noch Unterverzeichnisse. Flache Pfade sind gut für Windows.
  91. #leftpad Azer Koçulu vs. Kik über die Lizenz am Kik-Paket.

    Azer unpublished kik und 272 weitere Pakete (unter anderem left-pad). Es funktionieren reihenweise Pakete nicht mehr wegen fehlender Abhängigkeiten. module.exports = leftpad; function leftpad (str, len, ch) { //convert the `str` to String str = str +''; //needn't to pad len = len - str.length; if (len <= 0) return str; //convert the `ch` to String if (!ch && ch !== 0) ch = ' '; ch = ch + ''; var pad = ''; while (true) { if (len & 1) pad += ch; len >>= 1; if (len) ch += ch; else break; } return pad + str; }
  92. #leftpad Als Resultat aus dem leftpad-Problem, dürfen Pakete 24 Stunden

    nach ihrem initialen Publish nicht mehr unpublished werden.
  93. Reactive Extensions

  94. Reactive Extensions Ein Projekt, das aktiv von Microsoft Open Technologies

    und einer Open Source Community entwickelt wird. ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences. http://reactivex.io/intro.html
  95. Observables + Operators + Schedulers

  96. RxJS RxJS ist eine Implementierung der Reactive Extensions für JavaScript.

    Es gibt Implementierungen für die verschiedensten Umgebungen (z.B. C++, Python, Swift, PHP).
  97. Einbindung in Node.js var Rx = require('rx');
 var RxNode =

    require('rx-node'); $ npm install --save rx-node
  98. rx-node Das rx-node Paket erweitert den Funktionsumfang von RxJS um

    Node.js-spezifische Funktionalität wie z.B. toEventEmitter fromStream fromReadableStream …
  99. Observables günther gumhold / pixelio.de

  100. Observables Observer subscriben sich auf Observables. Observables versenden Informationen, die

    die Observer erhalten und daraufhin Funktionen ausführen.
  101. Observables 1. Observer definieren: Funktion die den Wert der asynchronen

    Operation verarbeitet
 2. Observable definieren: Asynchrone Operation definieren
 3. Observer auf das Observable subscriben
 4. Der Observer wird aufgerufen, sobald das Observable etwas sendet
  102. Observables var observer = Rx.Observer.create(
 x => console.log('Next: %s', x),

    // next
 err => console.log('Error: %s', err), //error
 () => console.log('Completed') // complete
 );
 
 var source = Rx.Observable.range(0, 3);
 
 var subscription = source.subscribe(observer);
  103. Hot vs. Cold Observables Hot: Beginnt, sobald es erstellt wurde

    Cold: Wartet, bis ein Observer sich subscribed
  104. Observables var RxNode = require('rx-node');
 
 RxNode.fromReadableStream(process.stdin)
 .subscribe(
 x =

    > console.log('Input data')
 );
  105. Operators Erich Westendarp / pixelio.de

  106. Operators Operatoren arbeiten mit Observables. Die meisten Operatoren geben Observables

    zurück und können dadurch verkettet werden.
  107. Erstellen von Observables var source = Rx.Observable.create(function (observer) {
 observer.onNext(42);


    observer.onCompleted();
 });
 
 var source2 = Rx.Observable.range(0, 10);
 
 var source3 = RxNode.fromReadableStream(process.stdin); Neue Observables erstellen
  108. Transform - map Rx.Observable.range(0, 10)
 .map(x => x * x)


    .subscribe(x => console.log(x));
 
 // 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 http://reactivex.io/documentation/operators/map.html
  109. Observables filtern var arr = [1, 2, 3, 2, 5,

    6, 4];
 
 var source = Rx.Observable.from(arr)
 .distinct() .filter(x => x % 2 === 0)
 .subscribe(x => console.log(x)); // 2, 6, 4 http://reactivex.io/documentation/operators/filter.html
  110. Den richtigen Operator finden http://reactivex.io/documentation/operators.html

  111. Scheduler Andreas Hermsdorf / pixelio.de

  112. Scheduler Bestimmen den Ausführungskontext, in dem ein Observable Nachrichten an

    seine Observer sendet. Viele Operatoren akzeptieren einen Scheduler z.B. Rx.Observable.range(start, count, [scheduler])
 Rx.Observable.from(iterable, [mapFn], [thisArg], [scheduler])
  113. Scheduler • null: Synchrone Ausführung • Rx.Scheduler.queue: Aufgaben werden in

    einer Warteschlange angeordnet • Rx.Scheduler.asap: Aufgabe wird zum nächstmöglichen Zeitpunkt ausgeführt
 • Rx.Scheduler.async: Asynchrone Ausführung
 • requestAnimationFrame: in RxJS-DOM
  114. Scheduler - synchron var source = Rx.Observable.range(1, 3);
 
 console.log('before

    subscribe');
 source.subscribe(
 (x) => { console.log('value ', x)
 });
 console.log('after subscribe');
 // before subscribe // value 1 // value 2 // value 3 // after subscribe
  115. Scheduler - asynchron var source = Rx.Observable.range(1, 3, Rx.Scheduler.async);
 


    console.log('just before subscribe');
 source.subscribe(
 (x) => { console.log('value ', x)
 });
 console.log('just after subscribe');
 
 // before subscribe // after subscribe // value 1 // value 2 // value 3
  116. Tools w.r.wagner / pixelio.de

  117. node-inspector

  118. node-inspector Node debugger basierend auf den Chrome Dev Tools.

  119. node-inspector $ npm install -g node-inspector $ node-debug index.js

  120. node-inspector

  121. pm2

  122. pm2 Process Manager 2 für Node.js. Monitoring, Logging und Prozessmanagement

    für Node.js-Applikationen.
  123. pm2 $ npm install -g pm2 $ pm2 start index.js

    $ pm2 list ┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ index │ 0 │ fork │ 20049 │ online │ 0 │ 4s │ 25.109 MB │ disabled │ └──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app
  124. pm2 - cluster mode $ pm2 start index.js -i $

    pm2 list ┌──────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ index │ 0 │ cluster │ 20368 │ online │ 0 │ 70s │ 27.391 MB │ disabled │ └──────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app $ pm2 scale index.js 2 [PM2] Scaling up application ┌──────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ index │ 0 │ cluster │ 20368 │ online │ 0 │ 108s │ 27.402 MB │ disabled │ │ index │ 1 │ cluster │ 20563 │ online │ 0 │ 0s │ 20.055 MB │ disabled │ └──────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app
  125. Fragen? Rainer Sturm / pixelio.de

  126. KONTAKT Sebastian Springer sebastian-springer@maibornwolff.de MaibornWolff GmbH Theresienhöhe 13 80339 München

    @basti_springer https://github.com/sspringer82