The event-driven nature of javascript – IPC2012
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
1,156
On Slideshare
1,156
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
9
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. MARTIN SCHUHFUSS | SPOT-MEDIA AGTHE EVENT-DRIVENNATURE OF JAVASCRIPT
  • 2. ÜBER MICHMARTIN SCHUHFUSS@usefulthink / Hamburger / ursprünglich PHP-Entwickler / Javascript-Nerd, Performance-Fetischist / node.js und interactive-development / Architekt und Entwickler bei spot-media
  • 3. UND IHR?
  • 4. JAVASCRIPT ?
  • 5. node.js ?
  • 6. WORUM GEHT‘S?
  • 7. THE EVENT-DRIVEN NATURE OF JAVASCRIPT
  • 8. SERVERSIDE JS ANDNON-BLOCKING I/O
  • 9. THE ASYNC NATURE OF JAVASCRIPT
  • 10. JAVASCRIPT EVENTS AND THE EVENT-LOOP
  • 11. zOMG, CALLBACKS EVERYWHERE
  • 12. JAVASCRIPT: THE BEST PART
  • 13. 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()
  • 14. 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!
  • 15. FIRST-CLASS FUNCTIONS// functions as parametersfunction call(fn) { return fn();}// passing an anonymous functioncall(function() { console.log("something");}); // "something"
  • 16. IMMEDIATE FUNCTIONSunmittelbar nach Deklaration ausgeführte Funktionen (function __immediatelyExecuted() { console.log("something"); } ()); // in short: (function() { ... } ());
  • 17. CLOSURES/ definieren scopes für Variablen/ ermöglichen private Variablen/ „einfrieren“ von Werten/ Ermöglichen „konfigurierbare“ Funktionen
  • 18. CLOSURES Scoping: „private“ Variablenvar 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…
  • 19. CLOSURES ALLES ZUSAMMEN// 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));
  • 20. CLOSURES „Konfigurierbare“ Funktionenvar 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));
  • 21. CLOSURES there is no block-scope…for(var i=0; i<3; i++) { setTimeout(function() { console.log("i=" + i); }, 0);}// -> i=3, i=3, i=3 WTF?
  • 22. CLOSURES Closures zum „einfrieren“ von Variablenfor(var i=0; i<3; i++) { (function(value) { setTimeout(function() { console.log("i=" + value); }, 0); } (i));}// -> i=0, i=1, i=2
  • 23. NON-BLOCKING FUNCTIONS
  • 24. ASYNC FUNCTIONS
  • 25. ASYNC FUNCTIONSASYNC FUNCTIONS ARE JAVASCRIPTS ANSWER TO position: absolute; Jed Schmidt, getting functional with (fab) – JSConf.eu 2010
  • 26. NON-BLOCKING FUNCTIONS / keine direkten Rückgabewerte / „Callbacks“ zur Fortsetzung des Programmablaufs / Background-Tasks übernehmen die Arbeit / keine Wartezeit innerhalb des Programms
  • 27. NON-BLOCKING FUNCTIONS var r = new XMLHttpRequest(); r.open("GET", "/foo/bar", true); r.onreadystatechange = function () { async „return“ if (r.readyState != 4 || r.status != 200) return; console.log("Success: " + r.responseText); }; r.send(); doesn‘t block execution! console.log("Request sent!");
  • 28. BLOCKING vs. NON-BLOCKING<?php var http = require(http);$browser = new BuzzBrowser(); http.get(http://google.com,$response = $browser function(res) { -> get(http://google.com); console.log(res); }echo $response; );echo done!; console.log(on the way!);https://github.com/kriswallsmith/Buzz http://nodejs.org/api/http.html
  • 29. BLOCKING vs. NON-BLOCKINGWHERE IS THE DIFFERENCE?
  • 30. BLOCKING vs. NON-BLOCKING WHERE IS THE DIFFERENCE? 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.logarithmic scale!CYCLES CPU 100 101 102 103 104 105 106 107 108 L1-Cache RAM HDD-Seek (~3 cycles, 1 ns) (~250 cycles, 83 ns) (~41,000,000 cycles, ~13.7ms)CPU-Registers L2-Cache NETWORK(~1 cycle, 0.33 ns) (~14 cycles, 4.7 ns) (~240,000,000 cycles, ~80ms) http://duartes.org/gustavo/blog/post/what-your-computer-does-while-you-wait
  • 31. BLOCKING vs. NON-BLOCKING WHERE IS THE DIFFERENCE?<?php$browser = new BuzzBrowser();$response = $browser Der php-Prozess blockiert während -> get(http://google.com); des Aufrufes und wird erst fortgesetzt, wenn $response verfügbar ist.echo $response;echo done!;
  • 32. BLOCKING vs. NON-BLOCKING WHERE IS THE DIFFERENCE? var http = require(http); http.get(http://google.com, function(res) { console.log(res); }node.js kann weiterarbeiten, ); während der Request im console.log(on the way!);Hintergrund bearbeitet wird.
  • 33. BLOCKING vs. NON-BLOCKING DIFFERENT SOLUTIONS/ Threads bzw. Prozesse (apache/fcgi/…) / Event-Loops/ während ein Thread / Thread-Pools (Background-Tasks) „schläft“ können andere Threads arbeiten / Alles wesentliche passiert in nur einem Prozess/ einfacher und intuitiver zu verstehen / Gehirnjogging – wann passiert was?/ Threads und Prozesse sind leider sehr teuer.
  • 34. INTRODUCING EVENTS
  • 35. INTRODUCING EVENTS/ Ereignisse auf die in der Software reagiert werden kann/ beliebig viele Quellen (üblicherweise nur eine)/ beliebig viele Empfänger
  • 36. 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, ...
  • 37. SERVER EVENTS/ I/O-events (networking, http, filesystem, …)/ timer-events/ custom-events (emitted by modules)
  • 38. EVENT-HANDLING: CALLBACKS / vereinfachte Event-Verarbeitung / wird anstelle eines return-Wertes aufgerufen / Konvention: function callback(err, data) {}
  • 39. 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.
  • 40. EVENT-HANDLING: EventEmitter // Beispiel EventEmitter / node.js-default var EventEmitter = require(events).EventEmitter, ee = new EventEmitter(); ee.on(food, function(data) { console.log(omnom!, data); }); ee.emit(myCustomEvent, { cookies: true }); // Beispiel jQuery var $doc = $(document); $doc.on(food, function() { console.log(omnom, data); }); $doc.triggerHandler(food, { cookies: true });
  • 41. REAL-LIFE EVENTS
  • 42. REAL-LIFE EVENTS Restaurant-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
  • 43. REAL-LIFE EVENTS Restaurant-Examplerestaurant.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); }); });});
  • 44. REAL-LIFE EVENTS Restaurant-ExampleLOOKS COMPLICATED?
  • 45. REAL-LIFE EVENTS the same, but with synchronous callswhile(true) { var guests = waitForGuests(); assignTable(guests); handoutMenues(guests); var order; while(order = guests.getOrder()) { guests.deliver( makeDrinks(order) ); guests.deliver( makeFood(order) ); }}
  • 46. REAL-LIFE EVENTS the 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
  • 47. REAL-LIFE EVENTS SO…
  • 48. REAL-LIFE EVENTS async is winning!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); }); }); });});
  • 49. REAL-LIFE EVENTS async 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
  • 50. REAL-LIFE EVENTS async is winning!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); }); }); });});
  • 51. THE EVENT-LOOP
  • 52. THEBASIC ARCHITECTURE EVENT-LOOP2 long-running operations (I/O) are handled by worker-threads 1 WORKER the code in the main program is THREADS executed and registers event- handlers for certain events. file = fs.createReadStream(...); file.on(data, myCallback); MAIN-PROCESS
  • 53. THEBASIC ARCHITECTURE EVENT-LOOP 3 once all code is executed, the event-loop starts WORKER EVENT-QUEUE waiting for incoming events.THREADS EVENT-LOOP file = fs.createReadStream(...); file.on(data, myCallback); MAIN-PROCESS
  • 54. THEBASIC ARCHITECTURE EVENT-LOOP 4 background-threads eventually fire events to send data to the main-program WORKER fs.end EVENT-QUEUETHREADS http.request fs.data EVENT-LOOP file = fs.createReadStream(...); file.on(data, myCallback); MAIN-PROCESS
  • 55. THEBASIC ARCHITECTURE EVENT-LOOP WORKER fs.end EVENT-QUEUE THREADS http.request fs.data5 for each event, the associated callbacks EVENT-LOOP are executed in the main process myCallback(data); MAIN-PROCESS
  • 56. THEBASIC ARCHITECTURE EVENT-LOOP 5 it is possible to add timerEvent custom events to the event-queue WORKER tickEventTHREADS fs.end http.request process.nextTick(callback); setTimeout(callback, 0); MAIN-PROCESS
  • 57. THEZUSAMMENFASSUNG EVENT-LOOP/ 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
  • 58. THE EVENT-LOOPNEVER BLOCK THE EVENT-LOOP
  • 59. THE EVENT-LOOP EDITIONNEVER BLOCK THE EVENT-LOOP – BROWSER $(.oh-my).on(click, function(req, res) { $.ajax(/somewhere, { will block the event-loop async: false, complete: function(jqXHR, respText) { AND the UI-Thread console.log(we‘re done!); } }); console.log(waited soo long!); is executed AFTER the the }); XHR completes everytime someone makes a synchronous XHR, god kills a kitten.
  • 60. THE EVENT-LOOPEDITIONNEVER BLOCK THE EVENT-LOOP – SERVER var running = true; process.nextTick(function() { is never called! running = false; }); while(running) { …because this never returns // ...whatever... }
  • 61. THE EVENT-LOOPEDITIONNEVER BLOCK THE EVENT-LOOP – SERVER var http = require(http), webserver = http.createServer(); webserver.on(request, function(req, res) { // some long-running calculation (e.g. image-processing) // or synchronous call no further request-processing res.end(finally done!); while this is running });
  • 62. THE EVENT-LOOP ASYNC FTW!var http = require(http), asyncService = require(./asyncService), webserver = http.createServer();webserver.on(request, function(req, res) { asyncService.startLongRunningOperation(); doesn‘t block asyncService.on(completed, function() { res.end(finally done!); });});
  • 63. THE EVENT-LOOP ASYNC FTW!// asyncService.jsvar spawn = require(child_process).spawn, EventEmitter = require(events).EventEmitter, service = new EventEmitter();service.startLongRunningOperation = function() { var child = spawn(sleep, [ 2 ]); takes 2 seconds to complete child.on(exit, function(code) { service.emit(completed); });};module.exports = service;
  • 64. THE FTW (BROWSER-EDITION)! ASYNC EVENT-LOOP$(#foo).on(click, function(ev) { // first part of something that takes some time window.setTimeout(function() { „pushed back“, allows other events // second part... to be processed in the meantime }, 0);});
  • 65. THE EVENT-LOOP ASYNC FTW!/ Wenns mal zu lange dauert: / child-process in node.js / web-worker im browser / „split and defer“: setTimeout(continuation, 0);
  • 66. zOMG, CALLBACKS EVERYWHERE
  • 67. 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); }); }); });});
  • 68. CALLBACK-HELLCOULD BE EVEN WORSE
  • 69. CALLBACK-HELL SOLUTION: EXTRACT FUNCTIONSrestaurant.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); }); });}
  • 70. WHAT IF FUNCTIONSDEPEND ON EACH OTHER?
  • 71. CALLBACK-HELL USE Step()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); });https://github.com/creationix/step
  • 72. WHAT IF WE NEED MULTIPLE RESPONSES
  • 73. CALLBACK-HELL USE Step()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); })
  • 74. QUESTIONS?
  • 75. THANKS!FEEDBACK https://joind.in/7340 MARTIN SCHUHFUSSSLIDES https://speakerdeck.com/u/usefulthink @usefulthink