Download - Einführung in Node.js
Monday, March 11, 13
WER BIN ICH?
• Sebastian Springer
• https://github.com/sspringer82
• @basti_springer
• Teamlead @ Mayflower
Monday, March 11, 13
THEMEN• Installation
• Node.js Shell
• Kernkomponenten
• NPM
• Events
• Streams
• HTTP
• Dateisystem
• Debugger
• Child_Process
• Cluster
• Tests
• Promises
Monday, March 11, 13
https://github.com/sspringer82/nodeworkshop
Monday, March 11, 13
INSTALLATION
Monday, March 11, 13
HTTP://NODEJS.ORG/DOWNLOAD/
Monday, March 11, 13
INSTALLATION
Monday, March 11, 13
INSTALLATIONAuf welchen Systemen ist Node.js verfügbar?
Monday, March 11, 13
INSTALLATION• Unix
• /usr/local/bin/node
• /usr/local/bin/npm
• /usr/local/lib/node_modules
• Windows
• C:\Program Files\nodejs\node.exe
• C:\Program Files\nodejs\npm
• C:\Program Files\nodejs\node_modules
Monday, March 11, 13
INSTALLATION
$ wget http://nodejs.org/dist/v0.8.21/node-v0.8.21.tar.gz...$ tar xvzf node-v0.8.21.tar.gz...$ cd node-v0.8.21/$ ./configure --prefix=/opt/node/node-v0.8.21...$ make...$ sudo make install...
Suchpfad anpassen!
Monday, March 11, 13
INSTALLATION
$ node --versionv0.8.22
Hat es funktioniert?
Monday, March 11, 13
REPL
Monday, March 11, 13
WHAT?
Monday, March 11, 13
READ-EVAL-PRINT-LOOP
DIE NODE.JS SHELL
Monday, March 11, 13
REPL
$ node> for (var i = 0; i < 3; i++) {... console.log(i);... }012undefined>
Monday, March 11, 13
REPL
.break Bricht ein Multiline Statement ab
.clear Zurücksetzen + .break (CTRL + C)
.exit Beendet die aktuelle Shell (CTRL + D)
.help Liste der Befehle
.save Speichert die aktuelle Session
.load Lädt eine gespeicherte Session
Monday, March 11, 13
KERNKOMPONENTEN
Monday, March 11, 13
KERNKOMPONENTENStandard Library
Node Bindings
V8 libuv
Eventloop async I/O
Monday, March 11, 13
KERNKOMPONENTENStandard Library
Node Bindings
V8 libuv
Eventloop async I/O
Monday, March 11, 13
KERNKOMPONENTEN
Monday, March 11, 13
KERNKOMPONENTENStandard Library
Node Bindings
V8 libuv
Eventloop async I/O
Monday, March 11, 13
KERNKOMPONENTENStandard Library
Node Bindings
V8 libuv
Eventloop async I/O
Monday, March 11, 13
V8
• Schneller Zugriff auf Eigenschaften
• Dynamische Erstellung von Maschinencode
• Garbage Collection
Monday, March 11, 13
V8 - FAST PROPERTY ACCESS
Monday, March 11, 13
V8 - FAST PROPERTY ACCESS
Monday, March 11, 13
V8 - FAST PROPERTY ACCESS
Monday, March 11, 13
MASCHINENCODE
Monday, March 11, 13
V8 - GARBAGE COLLECTION
• Programmausführung wird angehalten
• Es wird nur ein Teil des Object Heaps geprüft
• V8 kennt alle Objekte und Pointer im Speicher
Monday, March 11, 13
KERNKOMPONENTENStandard Library
Node Bindings
V8 libuv
Eventloop async I/O
libev + libeio IOCPMonday, March 11, 13
ASYNCHRONE OPERATIONEN
node.js Betriebssystem
Operation(z.B. lesen)
Monday, March 11, 13
APPLIKATIONEN IN NODE.JS
Monday, March 11, 13
APPLIKATIONEN IN NODE.JS
$ node helloWorld.js
Monday, March 11, 13
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X XX X X
Monday, March 11, 13
APPLIKATIONEN IN NODE.JSvar Star = function () { this.name = 'X', this.height = 20, this.step = 2;};
Star.prototype.top = function() { ...};
Star.prototype.print = function () { console.log(this.top().join('\n')); console.log(this.middle()); console.log(this.bottom().join('\n'));}
...
var star = new Star();star.print();
Monday, March 11, 13
DAS MODULSYSTEM
Monday, March 11, 13
DAS MODULSYSTEM
NPM
eigene Module
interne Module
Monday, March 11, 13
INTERNE MODULEAssertion Testing
BufferChild_Process
ClusterCrypto
DebuggerDNS
DomainEvent
File System
HTTPHTTPS
NetOsPath
ProcessQueryString
ReadlineREPL
Stream
String DecoderTimersTLS/SSL
TTYUDPURL
UtilitiesVMZLIB
Monday, March 11, 13
INTERNE MODULESTABILITÄTSINDEX
Index Name Beispiel
0 Deprecated util.pump
1 Experimental Domain, Cluster
2 Unstable Readline, Stream
3 Stable HTTP, Query String
4 API Frozen OS, Events
5 Locked Util, Assert
Monday, March 11, 13
VERWENDUNG INTERNER MODULE
var os = require('os');
console.log('Betriebssystem: ' + os.type() + ' ' + os.platform() + ' ' + os.release() + ' ' + os.arch());
intModule.js
Monday, March 11, 13
INTERNE MODULE - GLOBALS
• console
• process
• require
• Buffer
• set/clear-Timeout/Interval
• __filename + __dirname
Monday, March 11, 13
EIGENE MODULE
Monday, March 11, 13
EIGENE MODULE
• OH: “Wenn ich mir das Zeug, das in Node programmiert wurde, so ansehe, sieht das aus wie PHP3. Einfach von oben nach unten, alles in einer Datei”
• Liegen in einer separaten Datei
• Exportieren Klassen, Objekte oder Funktionen
• Können an anderer Stelle eingebunden werden
Monday, March 11, 13
EIGENE MODULE
exports.email = function (email) { var regex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/, result = regex.exec(email);
if (result) { return true; }
return false;};
validator.js
Monday, March 11, 13
EIGENE MODULE
exports.email = function (email) { var regex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/, result = regex.exec(email);
if (result) { return true; }
return false;};
validator.js
Monday, March 11, 13
VERWENDUNG EIGENER MODULE
var validator = require('./validator.js'), mail = ['[email protected]', 'Invalid Address'];
for (var i = 0; i < mail.length; i++) { if (validator.email(mail[i])) { console.log((i + 1) + '. Mailadresse ist gültig'); } else { console.log((i + 1) + '. Mailadresse ist ungültig'); }}
modules.js
Monday, March 11, 13
VERWENDUNG EIGENER MODULE
var validator = require('./validator.js'), mail = ['[email protected]', 'Invalid Address'];
for (var i = 0; i < mail.length; i++) { if (validator.email(mail[i])) { console.log((i + 1) + '. Mailadresse ist gültig'); } else { console.log((i + 1) + '. Mailadresse ist ungültig'); }}
modules.js
Monday, March 11, 13
EIGENE MODULE
$ node modules.js1. Mailadresse ist gültig2. Mailadresse ist ungültig
Monday, March 11, 13
Monday, March 11, 13
NPM
• Node Package Manager (von Isaac Schlueter)
• Bestandteil von Node.js seit 0.6.3
• https://github.com/isaacs/npm
Monday, March 11, 13
NPM - REPO
• Hier kommen die Pakete für das npm-Kommando her
• https://npmjs.org/
• Aktuell über 24.000 Pakete
• https://registry.npmjs.org/-/all/
Monday, March 11, 13
KOMMANDOS
• npm search <package>
• npm install <package>
• npm list
• npm update
• npm remove
Monday, March 11, 13
NPM SEARCH
$ npm se mysqlnpm http GET https://registry.npmjs.org/-/all/since?stale=update_aft...npm http 200 https://registry.npmjs.org/-/all/since?stale=update_aft...NAME DESCRIPTION AUTHOR DATE KEYWORDS...Accessor_M... A MySQL database wrapper... =bu 2012-1... mysql ac...any-db Database-agnostic connec... =grncdr 2013-0... mysql po...autodafe mvc framework for node w... =jifeon 2012-1... mvc fram...backbone-m... A sync module for Backbo... =ccowan 2012-1...caminte ORM for every database: ... =biggor 2013-0... caminte ...connect-my... a MySQL session store fo... =nathan 2012-0... connect-my... A MySQL session store fo... =daniel 2011-0...cormo ORM framework for Node.j... =croqui 2013-0... orm mong...
Monday, March 11, 13
NPM INSTALL$ npm in mysqlnpm http GET https://registry.npmjs.org/mysqlnpm http 200 https://registry.npmjs.org/mysqlnpm http GET https://registry.npmjs.org/bignumber.js/1.0.1npm http GET https://registry.npmjs.org/require-all/0.0.3npm http 200 https://registry.npmjs.org/require-all/0.0.3npm http GET https://registry.npmjs.org/require-all/-/requi...npm http 200 https://registry.npmjs.org/bignumber.js/1.0.1npm http GET https://registry.npmjs.org/bignumber.js/-/bign...npm http 200 https://registry.npmjs.org/require-all/-/requi...npm http 200 https://registry.npmjs.org/bignumber.js/-/[email protected] node_modules/mysql!"" [email protected]#"" [email protected]
Monday, March 11, 13
NPM LIST
$ npm ls/srv/node#"$ [email protected] !"" [email protected] #"" [email protected]
Monday, March 11, 13
NPM UPDATE
$ npm upnpm http GET https://registry.npmjs.org/mysqlnpm http 304 https://registry.npmjs.org/mysqlnpm http GET https://registry.npmjs.org/require-all/0.0.3npm http GET https://registry.npmjs.org/bignumber.js/1.0.1npm http 304 https://registry.npmjs.org/bignumber.js/1.0.1npm http 304 https://registry.npmjs.org/require-all/0.0.3
Monday, March 11, 13
NPM REMOVE
$ npm rm mysql$ npm ls/srv/node#"" (empty)
Monday, March 11, 13
EIGENE NPM-PAKETE
Monday, March 11, 13
{ "author": { "name": "Felix Geisendörfer", "email": "[email protected]", "url": "http://debuggable.com/" }, "name": "mysql", "description": "A node.js driver for mysql...", "version": "2.0.0-alpha7", "repository": { "url": "" }, "main": "./index", "scripts": { "test": "make test" }, "engines": { "node": "*" }, "dependencies": { "require-all": "0.0.3", "bignumber.js": "1.0.1" }, "devDependencies": { "utest": "0.0.6", "urun": "0.0.6", "underscore": "1.3.1" }, "optionalDependencies": {}, "readme": "# node-mysql\n\n[![Build Status]...", "readmeFilename": "Readme.md", "_id": "[email protected]", "_from": "mysql"}
Monday, March 11, 13
EIGENE NPM-PAKETE
• npm adduser
• Username, Passwort, E-Mail
• npm publish <folder>|<tarball>
Monday, March 11, 13
https://github.com/joyent/node/wiki/Modules
Monday, March 11, 13
EVENTS
Monday, March 11, 13
EVENTSEvent Emitter Subscriber
on(‘message’, function (e) {...
emit(‘message’, ‘data’)
Monday, March 11, 13
EVENTS
• Basis vieler Module
• Grundlage für eventgetriebene Architektur
• Ereignisse zum Informationsaustausch
• emit(event, [arg1], [arg2], [...]) - Publish
• on(event, listener) - Subscribe
Monday, March 11, 13
EVENTEMITTER
var EventEmitter = require('events').EventEmitter, util = require('util');
var MessageBus = function () {};
util.inherits(MessageBus, EventEmitter);
exports.MessageBus = MessageBus;
messageBus.js
Monday, March 11, 13
EVENTEMITTER
var MessageBus = require('./messageBus.js').MessageBus;
var mb = new MessageBus();
mb.on('message', function (data) { console.log('Received new message: ' + data)});
mb.emit('message', 'Hello World');
events.js
Monday, March 11, 13
EVENTEMITTER
$ node events.js Received new message: Hello World
Monday, March 11, 13
EVENTS
• Wo kommen Events zum Einsatz?
• child_process, cluster, dgram, domain, fs, http, net, readline, repl, stream, tls
Monday, March 11, 13
STREAMS
Monday, March 11, 13
STREAMS
• Repräsentieren Datenströme in Node.js
• Abstraktes Interface
• Les- und/oder schreibbare Streams
Monday, March 11, 13
READABLE STREAM
• Events
• data
• end
• error
• close
• Methoden
• pause
• resume
• destroy
• pipe
• setEncoding
Monday, March 11, 13
WRITABLE STREAM
• Events
• drain
• error
• close
• pipe
• Methoden
• write
• end
• destroy
• destroySoon
Monday, March 11, 13
STREAMS
• Wo kommen Streams zum Einsatz?
• fs, http, net repl, tls, zlib
Monday, March 11, 13
STREAMS IN DER PRAXIS?
Monday, March 11, 13
DER KLASSIKER
Monday, March 11, 13
HTTP-SERVER
var http = require('http');
http.createServer(function (req, res) { res.end('Hello World');}).listen(8080);
http.js
Monday, March 11, 13
HTTP-SERVER$ node http.js
Monday, March 11, 13
require('http').createServer(function (req, res) { var body, status, reqData;
if (req.headers['user-agent'].search(/MSIE/) != -1) { body = 'wrong Browser'; status = 403; } else { body = 'Hello Client'; status = 200; }
req.on('data', function (data) { reqData += data; }).on('end', function () { if (reqData) console.log(reqData); });
res.writeHead(status, { 'Content-Length': body.length, 'Content-Type': 'text/plain' }); res.write(body); res.end();}).listen(8080);
Monday, March 11, 13
HTTP-SERVER
• http.ServerRequest: Readable Stream
• http.ServerResponse: Writable Stream
Monday, March 11, 13
HTTP-CLIENT?
Monday, March 11, 13
var options = { hostname: 'www.google.de', port: 80, path: '/', method: 'get'};
var req = require('http').request(options, function(res) { console.log(res); res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('BODY: ' + chunk); });});
req.on('error', function(e) { console.log('problem with request: ' + e.message);});
req.write('data\n');req.end();
Monday, March 11, 13
var options = { hostname: 'www.google.de', port: 80, path: '/', method: 'get'};
var req = require('http').request(options, function(res) { console.log(res); res.setEncoding('utf8'); res.on('data', function (chunk) { console.log('BODY: ' + chunk); });});
req.write('data\n');req.end();
Monday, March 11, 13
DATEISYSTEM
Monday, March 11, 13
DATEISYSTEM-FUNKTIONEN
• exists
• readFile
• writeFile
• appendFile
• watchFile
• rename
• unlink
• chmod
• chown
• ...
Monday, March 11, 13
SYNC VS. ASYNC
Monday, March 11, 13
DATEI LESEN
var fs = require('fs') filename = process.argv[2] || 'input.txt';
fs.readFile(filename, 'utf8', function (err, data) { if (err) { console.error("File cound not be opened"); return false; } console.log(data); return true;});
Monday, March 11, 13
DATEI LESEN
$ node readFile.jsHello World!
Monday, March 11, 13
DATEI LESEN
$ node readFile.jsHello World!
$ node readFile.js nonexistant.txtFile cound not be opened
Monday, March 11, 13
FILE EXISTS$ ls -l input.txt -rw-r--r-- 1 sspringer staff 12 Mar 7 09:06 input.txt
Monday, March 11, 13
FILE EXISTS$ ls -l input.txt -rw-r--r-- 1 sspringer staff 12 Mar 7 09:06 input.txt
var fs = require('fs'), filename = process.argv[2] || 'input.txt';
fs.exists(filename, function (exists) { if (exists) { console.log('File exists'); return true; } console.error('There is no such file'); return false;});
Monday, March 11, 13
FILE EXISTS$ ls -l input.txt -rw-r--r-- 1 sspringer staff 12 Mar 7 09:06 input.txt
var fs = require('fs'), filename = process.argv[2] || 'input.txt';
fs.exists(filename, function (exists) { if (exists) { console.log('File exists'); return true; } console.error('There is no such file'); return false;});
$ node fileExists.jsFile exists
Monday, March 11, 13
APPEND FILE$ cat input.txtHello World!
Monday, March 11, 13
APPEND FILE$ cat input.txtHello World!
var fs = require('fs'), data = process.argv[2] || 'Hello my World';
fs.appendFile('input.txt', data, function (err) { if (err) { console.error('Could not write into file'); return false; } console.log('Success!'); return true;});
Monday, March 11, 13
APPEND FILE$ cat input.txtHello World!
var fs = require('fs'), data = process.argv[2] || 'Hello my World';
fs.appendFile('input.txt', data, function (err) { if (err) { console.error('Could not write into file'); return false; } console.log('Success!'); return true;});
$ node appendFile.js 'Hallo München!'Success!$ cat input.txt Hello World!Hallo München!
Monday, March 11, 13
WATCH FILEvar fs = require('fs');
fs.watch('input.txt', function (e) { if (e === 'change') { console.log('File changed'); } else if (e === 'rename') { console.log('File renamed'); }});
Monday, March 11, 13
WATCH FILE
$ node watchFile.js
var fs = require('fs');
fs.watch('input.txt', function (e) { if (e === 'change') { console.log('File changed'); } else if (e === 'rename') { console.log('File renamed'); }});
Monday, March 11, 13
WATCH FILE
$ echo 'Hello World!' > input.txt
$ node watchFile.js
var fs = require('fs');
fs.watch('input.txt', function (e) { if (e === 'change') { console.log('File changed'); } else if (e === 'rename') { console.log('File renamed'); }});
Monday, March 11, 13
WATCH FILE
$ echo 'Hello World!' > input.txt
$ node watchFile.js
$ node watchFile.js File changed
var fs = require('fs');
fs.watch('input.txt', function (e) { if (e === 'change') { console.log('File changed'); } else if (e === 'rename') { console.log('File renamed'); }});
Monday, March 11, 13
DEBUGGER
Monday, March 11, 13
BEISPIELCODEvar myObj = {a: 1, b: 2};
console.log(myObj);
myObj.a = 'Hello';
console.log(myObj);
for (var i = 0; i < 10; i++) { var helper = function () { // do something console.log(i) }; helper();}
Monday, March 11, 13
DEBUGGER
$ node debug debugger.js< debugger listening on port 5858connecting... okbreak in debugger.js:1 1 var myObj = {a: 1, b: 2}; 2 3 console.log(myObj);debug>
Monday, March 11, 13
DEBUGGER
$ node debug debugger.js< debugger listening on port 5858connecting... okbreak in debugger.js:1 1 var myObj = {a: 1, b: 2}; 2 3 console.log(myObj);debug>
Monday, March 11, 13
DEBUGGER - STEP
Kommando Bedeutung Beschreibung
n next Fortsetzen
c cont Step over
s step Step in
o out Step out
Monday, March 11, 13
DEBUGGER - WATCH
• watch(expression)
• unwatch(expression)
• watchers
Monday, March 11, 13
DEBUGGER - WATCH
debug> watch('myObj')debug> nbreak in debugger.js:3Watchers: 0: myObj = {"b":2,"a":1}
1 var myObj = {a: 1, b: 2}; 2 3 console.log(myObj); 4 5 myObj.a = 'Hello';debug>
Monday, March 11, 13
DEBUGGER - WATCH
debug> watch('myObj')debug> nbreak in debugger.js:3Watchers: 0: myObj = {"b":2,"a":1}
1 var myObj = {a: 1, b: 2}; 2 3 console.log(myObj); 4 5 myObj.a = 'Hello';debug>
Monday, March 11, 13
DEBUGGER - REPLdebug> replPress Ctrl + C to leave debug repl> myObj{ b: 2, a: 1 }> myObj.b = 14;14> myObj{ b: 14, a: 1 }debug> n< { a: 1, b: 14 }break in debugger.js:5Watchers: 0: myObj = {"b":14,"a":1}
3 console.log(myObj); 4 5 myObj.a = 'Hello'; 6 7 console.log(myObj);debug>
Monday, March 11, 13
DEBUGGER
• Kommandozeilen Debugger
• Kommandos
• Debugging einer Applikation
Monday, March 11, 13
CHILD_PROCESS
Monday, March 11, 13
CHILD_PROCESS
• spawn - Kommandoausführung
• exec - Kommandoausführung in Puffer
• execFile - Dateiausführung in Puffer
• fork - Node Prozess
Monday, March 11, 13
ETWAS RECHENINTENSIVES
module.exports = function () { var i, n = 1, results = 1; primeLoop: while (results < 300000) { n += 1; for (i = 2; i <= Math.sqrt(n); i += 1) { if (n % i === 0) { continue primeLoop; } } results += 1; } return n;};
cp1.js
Monday, March 11, 13
ETWAS BLOCKIERENDESpotenziell
var http = require('http');
http.createFakeServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
cp2.js
Monday, March 11, 13
ETWAS BLOCKIERENDES
var http = require('http'), prime = require('./cp1.js');
http.createServer(function (req, res) { console.time('Request answered in'); console.log('incoming Request');
var number = prime();
res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n');
console.timeEnd('Request answered in');}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
cp3.js
Monday, March 11, 13
ETWAS BLOCKIERENDES
$ node cp3.js Server running at http://127.0.0.1:1337/incoming RequestRequest answered in: 4713msincoming RequestRequest answered in: 4703ms
Monday, March 11, 13
DIE LÖSUNG: WIR FORKEN
Monday, March 11, 13
CHILD_PROCESS
var http = require('http');
http.createServer(function (req, res) { console.time('Request answered in'); console.log('incoming Request');
require('child_process').fork('./primeHelper.js') .on('message', function (data) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('The 300000st prime number is: ' + data.prime);
console.timeEnd('Request answered in'); });}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
cp4.js
Monday, March 11, 13
CHILD_PROCESS
primeHelper.js
var prime = require('./cp1.js')();
process.send({'prime': prime});
Monday, March 11, 13
CHILD_PROCESS
$ node cp4.js Server running at http://127.0.0.1:1337/incoming Requestincoming RequestRequest answered in: 4242msRequest answered in: 4913ms
Monday, March 11, 13
CHILD_PROCESS
• Threadmodell von Node.js
• Möglichkeiten von child_process - fork, spawn, exec
• Kommunikation zwischen Eltern- und Kindprozess
Monday, March 11, 13
CLUSTER
Monday, March 11, 13
CLUSTER
• Loadbalancing über CPU
• Funktioniert mit allen Instanzen von “net.Server”
• ...auch mit http
Monday, March 11, 13
var cluster = require('cluster'), http = require('http'), workers = 2;
if (cluster.isMaster) { for (var i = 0; i < workers; i++) { cluster.fork(); }} else { console.log('Worker ' + cluster.worker.process.pid + ' started');
http.createServer(function(req, res) {
console.log('Worker ' + cluster.worker.process.pid + ' responds');
res.writeHead(200); res.end("hello world\n"); }).listen(8000);}
cluster.js
Monday, March 11, 13
var http = require('http');
for (var i = 0; i < 100; i++) { http.get('http://localhost:8000', function (res) { console.log(res); });}
clusterClient.js
Monday, March 11, 13
CLUSTER
• node cluster.js
• node clusterClient.js
Monday, March 11, 13
CLUSTERWorker 38128 respondsWorker 38128 respondsWorker 38127 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 respondsWorker 38127 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 respondsWorker 38127 respondsWorker 38128 respondsWorker 38127 responds
Monday, March 11, 13
TESTING
Monday, March 11, 13
UNITTESTS
• Absicherung von Applikationen
• Tests auf Funktionsebene
• Node.js testet eigene Module ebenfalls
• Assert-Modul
• node-v0.8.22/test/simple
Monday, March 11, 13
ASSERTION TESTING
Monday, March 11, 13
ASSERTION TESTING
• var assert = require(‘assert’)
• Assertion-Methoden
• Sehr wenig Rückmeldung
• Nur ein Failure
Monday, March 11, 13
ASSERTION TESTINGfail Wirft einen
AssertionErrorok(value, [message]) Pass, wenn der Wert
true istequal(actual, expected, [message]) Vergleich mit ==
deepEqual(actual, expected, [message]) Vergleich über Strukturen
strictEqual(actual, expected, [message]) Vergleich mit ===
throws(block, [error], [message]) Pass, wenn eine Exception geworfen wird
NOT! - notEqual(...)Monday, March 11, 13
ASSERTION TESTING
var assert = require('assert'), actual = 'Hello World', expected = 'Hello World';
assert.equal(actual, expected, 'Strings are not Equal');
assert.notEqual(actual, expected, 'Strings are Equal');
assert.fail('FAIL!', 'PASS!', 'This fails!');
assert.js
Monday, March 11, 13
ASSERTION TESTING
$ node assert.js
assert.js:102 throw new assert.AssertionError({ ^AssertionError: Strings are Equal at Object.<anonymous> (/tmp/node/assert.js:7:8) at Module._compile (module.js:449:26) at Object.Module._extensions..js (module.js:467:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Module.runMain (module.js:492:10) at process.startup.processNextTick.process._tickCallback (node.js:244:9)
Monday, March 11, 13
NODEUNIT
Monday, March 11, 13
NODEUNIT
• npm install -g nodeunit
• Die gleichen Assertion-Methoden wie im Assert-Modul
• More verbose
• Mehrere Failures
Monday, March 11, 13
module.exports = { setUp: function (callback) { console.log('setUp'); callback(); }, tearDown: function (callback) { console.log('tearDown'); callback(); }, firstExample: function (test) { console.log('firstExample') test.equal('Hello', 'Hello', 'Strings are not Equal'); test.done(); }, exampleGroup: { secondExample: function (test) { test.notEqual('Hello', 'Hello', 'Strings are Equal'); test.done(); }, thirdExample: function (test) { test.fail('FAIL!', 'PASS!', 'This fails!'); test.done(); } }}
Monday, March 11, 13
$ nodeunit nodeunit.js
nodeunit.jssetUpfirstExampletearDown✔ firstExamplesetUptearDown✖ exampleGroup - secondExample
Assertion Message: Strings are EqualAssertionError: 'Hello World' != 'Hello World' at Object.assertWrapper [as notEqual] (...
setUptearDown✖ exampleGroup - thirdExample
AssertionError: 'FAIL!' undefined 'PASS!' at Object.assertWrapper [as fail] (...
FAILURES: 2/3 assertions failed (5ms)
Monday, March 11, 13
PROMISES
Monday, March 11, 13
PROMISES
• Ergebnis eines asynchronen Funktionsaufrufs
• Rückgabewert oder Exception
• Promise statt Blocking
• CommonJS Proposal
• Bis 0.2 Bestandteil von Node
Monday, March 11, 13
PYRAMID OF DOOM
step1(function (value1) { step2(value1, function (value2) { step3(value2, function (value3) { step3(value3, function (value4) { // do something }); }); });});
Monday, March 11, 13
PROMISES
Q.fcall(step1) .then(step2) .then(step3) .then(step4) .then(function (value4) { // do something with value 4 }, function (error) { // Handle any error from step1 through step4 }) .end();
Monday, March 11, 13
PROMISE-LIBRARIES
• https://github.com/kriskowal/q
• https://github.com/kriszyp/node-promise (lightweight)
• https://github.com/kriszyp/promised-io (complete API)
• ...
Monday, March 11, 13
OHNE PROMISESvar fs = require('fs');
fs.exists('input.txt', function (exists) { fs.stat('input.txt', function (err, stats) { fs.open('input.txt', 'r+', function (err, fd) { fs.read(fd, new Buffer(stats.size), 0, stats.size, null, function (err, read, buff) { if (err) throw err; console.log(buff.toString()); fs.close(fd, function () { console.log('File Handle closed'); }); } ) }); });});
Monday, March 11, 13
MIT PROMISES
Monday, March 11, 13
var fs = require('promised-io/fs'), gStat, gFd;
var open = function (stat) { gStat = stat; return fs.open('input.txt', 'r+'); }, read = function (fd) { gFd = fd; return fs.read(fd, new Buffer(gStat.size), 0, gStat.size, null); }, close = function (args) { console.log(args[1].toString()); return fs.close(gFd); }, catchall = function (err) { console.log(err); }, finished = function () { console.log('File Handle closed'); };
fs.stat('input.txt') .then(open) .then(read) .then(close) .then(finished, catchall);Monday, March 11, 13
AUSFÜHRUNG
$ node promises2.js Hello World
File Handle closed
Monday, March 11, 13
JETZT HABT IHR’S GESCHAFFT
Monday, March 11, 13
FRAGEN?
Monday, March 11, 13
KONTAKT
Sebastian [email protected]
Mayflower GmbHMannhardtstr. 680538 MünchenDeutschland
@basti_springer
https://github.com/sspringer82
Monday, March 11, 13
OHNE PROMISES
Monday, March 11, 13
OHNE PROMISES
Monday, March 11, 13
PROMISES
Monday, March 11, 13
PROMISES
Monday, March 11, 13
PROMISES
Monday, March 11, 13
PROMISES
Monday, March 11, 13