the event-driven nature of javascript – ipc2012

75
THE EVENT-DRIVEN NATURE OF JAVASCRIPT MARTIN SCHUHFUSS | SPOT-MEDIA AG

Upload: martin-schuhfuss

Post on 06-Jul-2015

1.092 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: The event-driven nature of javascript – IPC2012

THE EVENT-DRIVEN NATURE OF JAVASCRIPT

MARTIN SCHUHFUSS | SPOT-MEDIA AG

Page 2: The event-driven nature of javascript – IPC2012

ÜBER MICH

/ Hamburger

/ ursprünglich PHP-Entwickler

/ Javascript-Nerd, Performance-Fetischist

/ node.js und interactive-development

/ Architekt und Entwickler bei spot-media

MARTIN SCHUHFUSS@usefulthink

Page 3: The event-driven nature of javascript – IPC2012

UND IHR?

Page 4: The event-driven nature of javascript – IPC2012

JAVASCRIPT ?

Page 5: The event-driven nature of javascript – IPC2012

node.js ?

Page 6: The event-driven nature of javascript – IPC2012

WORUM GEHT‘S?

Page 7: The event-driven nature of javascript – IPC2012

THE EVENT-DRIVEN NATURE OF JAVASCRIPT

Page 8: The event-driven nature of javascript – IPC2012

SERVERSIDE JS ANDNON-BLOCKING I/O

Page 9: The event-driven nature of javascript – IPC2012

THE ASYNC NATURE OF JAVASCRIPT

Page 10: The event-driven nature of javascript – IPC2012

JAVASCRIPT EVENTS AND THE EVENT-LOOP

Page 11: The event-driven nature of javascript – IPC2012

zOMG, CALLBACKS EVERYWHERE

Page 12: The event-driven nature of javascript – IPC2012

JAVASCRIPT: THE BEST PART

Page 13: The event-driven nature of javascript – IPC2012

FIRST-CLASS FUNCTIONS/ Funktionen sind Objekte

/ …als Parameter

/ …als Rückgabewert

/ …in Variablenzuweisungen

/ Es gelten keine speziellen Regeln für Funktionen

/ Funktionen haben auch Eigenschaften und Methoden

/ z.B. fn.name oder fn.call() / fn.apply()

Page 14: The event-driven nature of javascript – IPC2012

FIRST-CLASS FUNCTIONS// a simple functionfunction something() { console.log("something"); }

// functions assigned as valuesvar aFunction = function() { /* ... */ }, somethingElse = something;

// function returning a functionfunction getFunction() { return function(msg) { console.log(msg); }}

var fn = getFunction();fn("foo"); // "foo"getFunction()("foo"); // works the same way!

Page 15: The event-driven nature of javascript – IPC2012

FIRST-CLASS FUNCTIONS

// functions as parametersfunction call(fn) { return fn();}

// passing an anonymous functioncall(function() { console.log("something");}); // "something"

Page 16: The event-driven nature of javascript – IPC2012

IMMEDIATE FUNCTIONS

(function __immediatelyExecuted() { console.log("something");} ());

// in short:(function() { ... } ());

unmittelbar nach Deklaration ausgeführte Funktionen

Page 17: The event-driven nature of javascript – IPC2012

CLOSURES

/ definieren scopes für Variablen

/ ermöglichen private Variablen

/ „einfrieren“ von Werten

/ Ermöglichen „konfigurierbare“ Funktionen

Page 18: The event-driven nature of javascript – IPC2012

CLOSURES

var deg2rad = (function() { var RAD_PER_DEG = Math.PI/180;

return function(deg) { return deg * RAD_PER_DEG; }}());

console.log(RAD_PER_DEG); // undefineddeg2Rad(180); // 3.1415926…

Scoping: „private“ Variablen

Page 19: The event-driven nature of javascript – IPC2012

CLOSURES

// for example to create a jQuery-plugin:(function($, window) { var somethingPrivate = null;

$.fn.extend({ plugin: function() { // here‘s the plugin-code

return this; } });} (this.jQuery, this));

ALLES ZUSAMMEN

Page 20: The event-driven nature of javascript – IPC2012

CLOSURES

var animate = (function(hasTransitions) { if(hasTransitions) { return function(params) { // animate using css-transitions }; } else { return function(params) { // animate using javascript, or better // don‘t animate at all. };}(Modernizr.csstransitions));

„Konfigurierbare“ Funktionen

Page 21: The event-driven nature of javascript – IPC2012

CLOSURES

for(var i=0; i<3; i++) { setTimeout(function() { console.log("i=" + i); }, 0);}

// -> i=3, i=3, i=3

there is no block-scope…

WTF?

Page 22: The event-driven nature of javascript – IPC2012

CLOSURES

for(var i=0; i<3; i++) { (function(value) { setTimeout(function() { console.log("i=" + value); }, 0); } (i));}

Closures zum „einfrieren“ von Variablen

// -> i=0, i=1, i=2

Page 23: The event-driven nature of javascript – IPC2012

NON-BLOCKING FUNCTIONS

Page 24: The event-driven nature of javascript – IPC2012

ASYNC FUNCTIONS

Page 25: The event-driven nature of javascript – IPC2012

ASYNC FUNCTIONSASYNC FUNCTIONS ARE JAVASCRIPTS

ANSWER TO position: absolute;Jed Schmidt, getting functional with (fab) – JSConf.eu 2010

Page 26: The event-driven nature of javascript – IPC2012

NON-BLOCKING FUNCTIONS

/ keine direkten Rückgabewerte

/ „Callbacks“ zur Fortsetzung des Programmablaufs

/ Background-Tasks übernehmen die Arbeit

/ keine Wartezeit innerhalb des Programms

Page 27: The event-driven nature of javascript – IPC2012

NON-BLOCKING FUNCTIONS

var r = new XMLHttpRequest();r.open("GET", "/foo/bar", true);

r.onreadystatechange = function () { if (r.readyState != 4 || r.status != 200) return;

console.log("Success: " + r.responseText);};

r.send();console.log("Request sent!");

doesn‘t block execution!

async „return“

Page 28: The event-driven nature of javascript – IPC2012

BLOCKING vs. NON-BLOCKING<?php

$browser = new Buzz\Browser();$response = $browser -> get('http://google.com');

echo $response;echo 'done!';

var http = require('http');

http.get('http://google.com', function(res) { console.log(res); });console.log('on the way!');

https://github.com/kriswallsmith/Buzz http://nodejs.org/api/http.html

Page 29: The event-driven nature of javascript – IPC2012

BLOCKING vs. NON-BLOCKING

WHERE IS THE DIFFERENCE?

Page 30: The event-driven nature of javascript – IPC2012

CPU-Registers(~1 cycle, 0.33 ns)

L1-Cache(~3 cycles, 1 ns)

L2-Cache(~14 cycles, 4.7 ns)

http://duartes.org/gustavo/blog/post/what-your-computer-does-while-you-wait

RAM(~250 cycles, 83 ns)

HDD-Seek(~41,000,000 cycles, ~13.7ms)

NETWORK(~240,000,000 cycles, ~80ms)

100

101

102

103

104

105

106

107

108

CP

UC

YCLE

S

if a single Instruction would take 1 second to execute, the HTTP-request to google.com would

require us to wait for 8 years and more.

BLOCKING vs. NON-BLOCKINGWHERE IS THE DIFFERENCE?

logarithmic scale!

Page 31: The event-driven nature of javascript – IPC2012

BLOCKING vs. NON-BLOCKING

<?php

$browser = new Buzz\Browser();$response = $browser -> get('http://google.com');

echo $response;echo 'done!';

WHERE IS THE DIFFERENCE?

Der php-Prozess blockiert während des Aufrufes und wird erst fortgesetzt, wenn $response verfügbar ist.

Page 32: The event-driven nature of javascript – IPC2012

BLOCKING vs. NON-BLOCKING

var http = require('http');

http.get('http://google.com', function(res) { console.log(res); });console.log('on the way!');

WHERE IS THE DIFFERENCE?

node.js kann weiterarbeiten, während der Request im

Hintergrund bearbeitet wird.

Page 33: The event-driven nature of javascript – IPC2012

BLOCKING vs. NON-BLOCKINGDIFFERENT SOLUTIONS

/ Threads bzw. Prozesse (apache/fcgi/…)

/ während ein Thread „schläft“ können andere Threads arbeiten

/ einfacher und intuitiver zu verstehen

/ Threads und Prozesse sind leider sehr teuer.

/ Event-Loops

/ Thread-Pools (Background-Tasks)

/ Alles wesentliche passiert in nur einem Prozess

/ Gehirnjogging – wann passiert was?

Page 34: The event-driven nature of javascript – IPC2012

INTRODUCING EVENTS

Page 35: The event-driven nature of javascript – IPC2012

INTRODUCING EVENTS

/ Ereignisse auf die in der Software reagiert werden kann

/ beliebig viele Quellen (üblicherweise nur eine)

/ beliebig viele Empfänger

Page 36: The event-driven nature of javascript – IPC2012

EVENTS IM BROWSER/ UI-events: resize, scroll, ...

/ user interaction-events: mouse*, key*, …

/ timer events: setTimeout(), setInterval()

/ render-events: requestAnimationFrame()

/ resource-events: load, readystatechange, …

/ navigation-events: hashchange, popstate, ...

/ communication-events: message, ...

Page 37: The event-driven nature of javascript – IPC2012

SERVER EVENTS

/ I/O-events (networking, http, filesystem, …)

/ timer-events

/ custom-events (emitted by modules)

Page 38: The event-driven nature of javascript – IPC2012

EVENT-HANDLING: CALLBACKS

/ vereinfachte Event-Verarbeitung

/ wird anstelle eines return-Wertes aufgerufen

/ Konvention: function callback(err, data) {}

Page 39: The event-driven nature of javascript – IPC2012

EVENT-HANDLING: EventEmitter/ Event-Quelle und Dispatcher

/ Listener für bestimmte Events werden mit on(evName, callback) angemeldet.

/ Events werden mit emit() (node.js) oder trigger() bzw. triggerHandler() (jQuery) ausgelöst

/ Events werden nur an die Listener für das Event in dem Event-Emitter gesendet.

Page 40: The event-driven nature of javascript – IPC2012

EVENT-HANDLING: EventEmitter

// Beispiel EventEmitter / node.js-defaultvar EventEmitter = require('events').EventEmitter, ee = new EventEmitter();

ee.on('food', function(data) { console.log('omnom!', data); });ee.emit('myCustomEvent', { cookies: true });

// Beispiel jQueryvar $doc = $(document);

$doc.on('food', function() { console.log('omnom', data); });$doc.triggerHandler('food', { cookies: true });

Page 41: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTS

Page 42: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTSRestaurant-Example

/ Ein Gast betritt ein Restaurant

/ … Kellner weist einen Tisch zu

/ … Kellner verteilt Speisekarten

/ Der Gast gibt eine Bestellung auf; der Kellner…

/ … gibt Getränkebestellungen an Barkeeper weiter

/ … gibt Essensbestellungen an Küche weiter

Page 43: The event-driven nature of javascript – IPC2012

restaurant.on('newGuestEnters', function(guests) { assignTable(guests);

guest.on('seated', function() { guests.handout(menue); });

// this might actually happen more than once... guests.on('order', function(order) { kitchenWorker.send(order.getMeals()); kitchenWorker.on('mealsReady', function(meals) { guest.deliver(meals); });

barkeeper.send(order.getDrinks()); barkeeper.on('drinksReady', function(drinks) { guest.deliver(drinks); }); });});

REAL-LIFE EVENTSRestaurant-Example

Page 44: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTS

LOOKS COMPLICATED?

Restaurant-Example

Page 45: The event-driven nature of javascript – IPC2012

while(true) { var guests = waitForGuests();

assignTable(guests); handoutMenues(guests);

var order; while(order = guests.getOrder()) { guests.deliver( makeDrinks(order) ); guests.deliver( makeFood(order) ); }}

REAL-LIFE EVENTSthe same, but with synchronous calls

Page 46: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTSthe same, but with synchronous calls

/ nur 1 Gast je Kellner

/ n gleichzeitige Gäste brauchen n Kellner (= Threads)

/ n Kellner und m>n Gäste: Warteschlange am Eingang

/ schlafende Kellner

Page 47: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTS

SO…

Page 48: The event-driven nature of javascript – IPC2012

restaurant.on('newGuestEnters', function(guests) { waiter.assignTable(guests);

guests.on('seated', function() { guests.handout(menue);

// this might actually happen more than once... guests.on('order', function(order) { kitchenWorker.send(order.getMeals()); kitchenWorker.on('mealsReady', function(meals) { guests.deliver(meals); }); barkeeper.send(order.getDrinks()); barkeeper.on('drinksReady', function(drinks) { guests.deliver(drinks); }); }); });});

REAL-LIFE EVENTSasync is winning!

Page 49: The event-driven nature of javascript – IPC2012

REAL-LIFE EVENTSasync is winning!

/ nur 1 Kellner für n gleichzeitige Gäste

/ zu viele Gäste führen zu langsamerer Asuführung

/ Zubereitung wird von Hintergrund-Services erledigt (barkeeper/kitchenWorker)

/ jegliche Aktion wird über Events ausgelöst

/ Kellner sind nur untätig, wenn

Page 50: The event-driven nature of javascript – IPC2012

restaurant.on('newGuestEnters', function(guests) { waiter.assignTable(guests);

guests.on('seated', function() { guests.handout(menue);

// this might actually happen more than once... guests.on('order', function(order) { kitchenWorker.send(order.getMeals()); kitchenWorker.on('mealsReady', function(meals) { guests.deliver(meals); }); barkeeper.send(order.getDrinks()); barkeeper.on('drinksReady', function(drinks) { guests.deliver(drinks); }); }); });});

REAL-LIFE EVENTSasync is winning!

Page 51: The event-driven nature of javascript – IPC2012

THE EVENT-LOOP

Page 52: The event-driven nature of javascript – IPC2012

THE EVENT-LOOP

MAIN-PROCESSfile = fs.createReadStream(...);file.on('data', myCallback);

BASIC ARCHITECTURE

the code in the main program is executed and registers event-

handlers for certain events.

1WORKER

THREADS

long-running operations (I/O) are handled by

worker-threads

2

Page 53: The event-driven nature of javascript – IPC2012

WORKERTHREADS

THE EVENT-LOOPBASIC ARCHITECTURE

MAIN-PROCESSfile = fs.createReadStream(...);file.on('data', myCallback);

EVENT-LOOP

EVENT-QUEUE

once all code is executed, the event-loop starts

waiting for incoming events.

3

Page 54: The event-driven nature of javascript – IPC2012

WORKERTHREADS

THE EVENT-LOOPBASIC ARCHITECTURE

MAIN-PROCESSfile = fs.createReadStream(...);file.on('data', myCallback);

EVENT-LOOP

EVENT-QUEUE

background-threads eventually fire events

to send data to the main-program

4

fs.data

http.request

fs.end

Page 55: The event-driven nature of javascript – IPC2012

WORKERTHREADS

THE EVENT-LOOPBASIC ARCHITECTURE

MAIN-PROCESSmyCallback(data);

EVENT-LOOP

EVENT-QUEUEhttp.request

fs.end

for each event, the associated callbacks are executed in the

main process

5fs.datafs.data

Page 56: The event-driven nature of javascript – IPC2012

WORKERTHREADS

THE EVENT-LOOPBASIC ARCHITECTURE

MAIN-PROCESSprocess.nextTick(callback);setTimeout(callback, 0);

http.request

fs.end

it is possible to add custom events to the

event-queue

5

tickEvent

timerEvent

Page 57: The event-driven nature of javascript – IPC2012

THE EVENT-LOOPZUSAMMENFASSUNG

/ keine Parallelisierung

/ Verarbeitung in Reihenfolge der Erzeugung

/ alles wesentliche in nur einem Prozess

/ separate Prozesse für CPU-Intensive Tasks

/ zwingt zum Schreiben von asynchronem Code

Page 58: The event-driven nature of javascript – IPC2012

THE EVENT-LOOP

NEVER BLOCK THE EVENT-LOOP

Page 59: The event-driven nature of javascript – IPC2012

$('.oh-my').on('click', function(req, res) { $.ajax('/somewhere', { async: false, complete: function(jqXHR, respText) { console.log('we‘re done!'); } });

console.log('waited soo long!');});

NEVER BLOCK THE EVENT-LOOP – BROWSER EDITIONTHE EVENT-LOOP

everytime someone makes a synchronous XHR, god kills a kitten.

will block the event-loopAND the UI-Thread

is executed AFTER the theXHR completes

Page 60: The event-driven nature of javascript – IPC2012

var running = true;

process.nextTick(function() { running = false;});

while(running) { // ...whatever...}

NEVER BLOCK THE EVENT-LOOP – SERVER EDITIONTHE EVENT-LOOP

is never called!

…because this never returns

Page 61: The event-driven nature of javascript – IPC2012

var http = require('http'), webserver = http.createServer();

webserver.on('request', function(req, res) { // some long-running calculation (e.g. image-processing) // or synchronous call

res.end('finally done!');});

THE EVENT-LOOP

no further request-processing while this is running

NEVER BLOCK THE EVENT-LOOP – SERVER EDITION

Page 62: The event-driven nature of javascript – IPC2012

var http = require('http'), asyncService = require('./asyncService'), webserver = http.createServer();

webserver.on('request', function(req, res) { asyncService.startLongRunningOperation(); asyncService.on('completed', function() { res.end('finally done!'); });});

ASYNC FTW!THE EVENT-LOOP

doesn‘t block

Page 63: The event-driven nature of javascript – IPC2012

// asyncService.jsvar spawn = require('child_process').spawn, EventEmitter = require('events').EventEmitter,

service = new EventEmitter();

service.startLongRunningOperation = function() { var child = spawn('sleep', [ 2 ]); child.on('exit', function(code) { service.emit('completed'); });};

module.exports = service;

ASYNC FTW!THE EVENT-LOOP

takes 2 seconds to complete

Page 64: The event-driven nature of javascript – IPC2012

$('#foo').on('click', function(ev) { // first part of something that takes some time

window.setTimeout(function() { // second part... }, 0);});

ASYNC FTW (BROWSER-EDITION)!THE EVENT-LOOP

„pushed back“, allows other events to be processed in the meantime

Page 65: The event-driven nature of javascript – IPC2012

ASYNC FTW!THE EVENT-LOOP

/ Wenns mal zu lange dauert:

/ child-process in node.js

/ web-worker im browser

/ „split and defer“: setTimeout(continuation, 0);

Page 66: The event-driven nature of javascript – IPC2012

zOMG, CALLBACKS EVERYWHERE

Page 67: The event-driven nature of javascript – IPC2012

CALLBACK-HELLrestaurant.on('newGuestEnters', function(guests) { assignTable(guests);

guests.on('seated', function() { guests.handout(menue);

// this might actually happen more than once... guests.on('order', function(order) { kitchenWorker.send(order.getMeals()); kitchenWorker.on('mealsReady', function(meals) { guests.deliver(meals); }); barkeeper.send(order.getDrinks()); barkeeper.on('drinksReady', function(drinks) { guests.deliver(drinks); }); }); });});

Page 68: The event-driven nature of javascript – IPC2012

CALLBACK-HELL

COULD BE EVEN WORSE

Page 69: The event-driven nature of javascript – IPC2012

restaurant.on('newGuestEnters', function(guests) { assignTable(guests);

guests.on('seated', function() { guests.handout(menue); attachOrderHandling(guests); });});

function attachOrderHandling(guests) { guests.on('order', function(order) { kitchenWorker.send(order.getMeals()); kitchenWorker.on('mealsReady', function(meals) { guests.deliver(meals); });

barkeeper.send(order.getDrinks()); barkeeper.on('drinksReady', function(drinks) { guests.deliver(drinks); }); });}

CALLBACK-HELLSOLUTION: EXTRACT FUNCTIONS

Page 70: The event-driven nature of javascript – IPC2012

WHAT IF FUNCTIONS DEPEND ON EACH OTHER?

Page 71: The event-driven nature of javascript – IPC2012

Step( function readSelf() { fs.readFile(__filename, this); }, function capitalize(err, text) { if(err) { throw err; } return text.toUpperCase(); }, function showIt(err, newText) { if(err) { throw err; } console.log(newText); });

CALLBACK-HELLUSE Step()

https://github.com/creationix/step

Page 72: The event-driven nature of javascript – IPC2012

WHAT IF WE NEED MULTIPLE RESPONSES

Page 73: The event-driven nature of javascript – IPC2012

Step( // Loads two files in parallel function loadStuff() { fs.readFile(__filename, this.parallel()); fs.readFile("/etc/passwd", this.parallel()); }, // Show the result when done function showStuff(err, code, users) { if (err) throw err;

console.log(code); console.log(users); })

CALLBACK-HELLUSE Step()

Page 74: The event-driven nature of javascript – IPC2012

QUESTIONS?

Page 75: The event-driven nature of javascript – IPC2012

THANKS!

FEEDBACK https://joind.in/7340 MARTIN SCHUHFUSS@usefulthinkSLIDES https://speakerdeck.com/u/usefulthink