Your SlideShare is downloading. ×
@crichardsonNodeJS: the good parts?A skeptic’s viewChris RichardsonAuthor of POJOs in ActionFounder of the original CloudF...
@crichardsonPresentation goalHow a curmudgeonlyserver-side Java developerdiscovered an appreciationfor NodeJS and JavaScript
@crichardsonAbout Chris
@crichardson(About Chris)
@crichardsonAbout Chris()
@crichardsonAbout Chris
@crichardsonAbout Chrishttp://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
@crichardsonvmc push About-ChrisDeveloper AdvocateSignup at http://cloudfoundry.com
@crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
@crichardsonWhat’s NodeJS?Designed for DIRTy apps
@crichardsonSmall but growing rapidlyBusy!
@crichardsonNodeJS Hello Worldapp.js$ node app.js$ curl http://localhost:1337http://nodejs.org/Load a modulerequest handler
@crichardsonNodeJSJavaScriptReactorpatternModules
@crichardsonNodeJSJavaScriptReactorpatternModules
@crichardsonDynamic, weakly-typedDynamic:Types are associated with values - not variablesDefine new program elements at run...
@crichardsonJavaScript is object-oriented> var fred = {name: “Fred”, gender: “Male”};undefined> fred.name“Fred”> console.lo...
@crichardsonJavaScript “classes”function Person(name) {this.name = name;}Person.prototype.sayHello = function () { console...
@crichardsonoverridesJavaScript is a prototypallanguage__proto__a 99__proto__a 100b 200inheritedPrototypeXY
@crichardsonPrototypal code$ node> var person = {};undefined> person.sayHello = function () { console.log("Hello " + this.n...
@crichardsonJavaScript is Functionalfunction makeGenerator(nextFunction) {var value = 0;return function() {var current = v...
@crichardsonPartial function application> var join = require("path").join;undefined> join("/x", "y")/x/y> var withinx = joi...
@crichardsonCreated in a hurry with thegoal of looking like JavaThe ‘Java...’ name creates expectations that it can’t sati...
@crichardsonJavaScript is the only way toget things done in thebrowser
@crichardsonStockholm syndrome“Stockholm syndrome ... is a psychologicalphenomenon in which hostages ... havepositive feel...
@crichardsonMartin Fowler once said:"...Im one of those who despairs that alanguage with such deep flaws plays such animpor...
@crichardsonUse just the good parts
@crichardsonUse a better language thatcompiles to JavaScriptTypeScriptTyped parameters and fieldsClasses and interfaces (dy...
@crichardsonCoffeeScript Hello Worldhttp = require(http)class HttpRequestHandlerconstructor: (@message) ->handle: (req, re...
@crichardsonNodeJSJavaScriptReactorpatternModules
@crichardsonAbout the Reactor patternDefined by Doug Schmidt in 1995Pattern for writing scalable serversAlternative to thre...
@crichardsonReactor pattern structureEvent Handlerhandle_event(type)get_handle()Initiation Dispatcherhandle_events()regist...
@crichardsonBenefits:Separation of concerns - event handlers separatedfrom low-level mechanismMore efficient - no thread con...
@crichardsonDrawbacks:Non-pre-emptive - handlers can’t block/take a longtimeDifficult to understand and debug - inverted flo...
@crichardsonNodeJS event loop implementsthe Reactor pattern
@crichardsonApplication codeEvent-driven architectureNodeJS event loopBasic networking/file-system/etc.HTTP DB driver ...Ev...
@crichardsonGetting notified: Callbackexamplevar fs = require("fs");function statFile(path) {fs.stat(path, function (err, s...
@crichardsonGetting notified: eventlistenersEventEmitter class - inherit or useListener registration methods:on(eventName, ...
@crichardsonEvent listener examplevar fs = require("fs");var readStream = fs.createReadStream("events.js", {encoding: "utf...
@crichardsonCallback hellfunction times2(x, callback) {setTimeout(function () {callback(x * 2)}, 500);}function plus3(x, c...
@crichardsonLong running computationsLong running computation blocks event loop forother requestsNeed to run outside of ma...
@crichardsonUsing child processesvar child = require(child_process).fork(child.js);function sayHelloToChild() {child.send(...
@crichardsonNodeJSJavaScriptReactorpatternModules
Core built-in modulesBasic networkingHTTP(S)FilesystemEventsTimers...
@crichardsonThousands of communitydeveloped moduleshttps://npmjs.org/web frameworks, SQL/NoSQLdatabase, drivers, messaging...
@crichardsonWhat’s a module?One or more JavaScript filesOptional native code:Compiled during installationJavaScript != syst...
@crichardsonEasy to install$ npm install package-name
@crichardsonEasy to usevar http = require(“http”)var server = http.createServer...Core module ORPath to file ORmodule in no...
@crichardsonDeveloping with NodeJSmodulesCore modulesCommunity modulesYour modulesApplication code
@crichardsonLots of modules BUT...Variable qualityMultiple incomplete MySQL drivers, e.g. withoutconnection pooling!Often ...
@crichardsonTo summarizeNodeJSJavaScriptReactor patternModulesFlawed andmisunderstoodScalable yetcostly andoftenunnecessar...
@crichardsonAlternative technologiesAtmosphere - portable event deliveryNetty - asynchronous I/OVert.xSpringSource’s React...
@crichardsonSo why care aboutNodeJS?Easy to write scalable network servicesEasy to push events to the browserEasy to get (...
@crichardsonEvolving from a monolithicarchitecture....WARShippingServiceAccountingServiceInventoryServiceStoreFrontUI
@crichardson... to a micro-service architectureStore front web applicationshipping web applicationinventory web applicatio...
@crichardsonBrowserWARStoreFrontUIModelView ControllerPresentation layer evolution....HTML / HTTP+JavaScript
@crichardsonBrowser Web applicationRESTfulEndpointsModelView Controller...Presentation layer evolutionJSON-RESTHTML 5 -Jav...
@crichardsonNodeJS as an API gatewayBrowserService 1Service 2MessageBusHTML 5/JavaScriptSocket.ioclientEventsRESTful WSSer...
@crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
@crichardsonServing static content
@crichardsonUsing low-level APIsvar http = require(http), path = require(path), mime = require(mime), fs = require("fs");v...
@crichardsonUsing the express webframeworkvar express = require(express), http = require(http), app = express(), server = ...
@crichardsonRESTful web services
@crichardsonImplementing RESTful WSwith Expressvar express = require(express),http = require(http),path = require(path);va...
@crichardsonProxying to backend serverexpress = require(express)request = require(request)app = express.createServer()prox...
@crichardsonDelivering events to thebrowser
@crichardsonNodeJS clock exampleIncrements everysecond
@crichardsonSocket.io - Server sidevar express = require(express), http = require(http), app = express(), server = http.cr...
@crichardsonSocket.io - client side using theknockout.js MVVM frameworkvar socket = io.connect(location.hostname);function...
@crichardsonDistributed NodeJS clockexampleBrowser NodeJS NodeJSRabbitMQProducerConsumersocket.iosocket.io
@crichardsonAMQP Publishervar amqp = require(amqp),amqpConnection = amqp.createConnection(...),tickTockExchange;function t...
@crichardsonAMQP socket.iovar express = require(express), http = require(http), amqp = require(‘amqp’)....;server.listen(8...
@crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
@crichardsonAsync code = callback hellScenarios:Sequential: A B CFork and join: A and B CCode quickly becomes very messy
@crichardsonSimplifying code withPromises (a.k.a. Futures)Functions return a promise - no callback parameterA promise repr...
@crichardsonTaming callback hell 1function times2(x) {var deferred = when.defer();setTimeout(function () {deferred.resolve...
@crichardsonTaming callback hell 2function sum(a, b) {var deferred = when.defer();setTimeout(function () {deferred.resolve...
@crichardsonCalling non-promise codevar deferred = when.defer();fs.stat(path, function (err, statInfo) {if (err)deferred.r...
@crichardsonFilesystem scanner exampleRead contents of directoryUse stat to determine if directory or fileRecurse on direct...
@crichardsonRead contents of directoryfunction findFilesInDir(dir) {var directoryContents =nodefn.call(self.fs.readdir, di...
@crichardsonCreate absolute pathsfunction findFilesInDir(dir) {var directoryContents = ...var toAbsolute = join.bind(undef...
@crichardsonUse stat to determine ifdirectory or filefunction findFilesInDir(dir) {var directoryContents = ...var absoluteP...
@crichardsonRecurse on directoriesfunction findFilesInDir(dir) {...var statResults = ...;var listOfListsOfFiles =when.map(...
@crichardsonFlatten array of arrays of filepathsfunction findFilesInDir(dir) {...var listOfListsOfFiles = ...;return when.r...
@crichardsonSummaryJavaScript is a very flawed languageThe asynchronous model is often unnecessary; veryconstraining; and a...
@crichardsonQuestions?@crichardson chris.richardson@springsource.comhttp://plainoldobjects.com - code and slideswww.cloudf...
Upcoming SlideShare
Loading in...5
×

NodeJS: the good parts? A skeptic’s view (jax jax2013)

12,926

Published on

JavaScript used to be confined to the browser. But these days, it's becoming increasingly popular in server-side applications in the form of Node.js. Node.js provides event-driven, non-blocking I/O model that supposedly makes it easy to build scalable network application. In this talk you will learn about the consequences of combining the event-driven programming model with a prototype-based, weakly typed, dynamic language. We will share our perspective as a server-side Java developer who wasn’t entirely happy about JavaScript in the browser, let alone on the server. You will learn how to use Node.js effectively in modern, polyglot applications.

Watch the video: http://www.youtube.com/watch?v=CN0jTnSROsk&feature=youtu.be

Published in: Technology

Transcript of "NodeJS: the good parts? A skeptic’s view (jax jax2013)"

  1. 1. @crichardsonNodeJS: the good parts?A skeptic’s viewChris RichardsonAuthor of POJOs in ActionFounder of the original CloudFoundry.com@crichardsonchris.richardson@springsource.comhttp://plainoldobjects.com
  2. 2. @crichardsonPresentation goalHow a curmudgeonlyserver-side Java developerdiscovered an appreciationfor NodeJS and JavaScript
  3. 3. @crichardsonAbout Chris
  4. 4. @crichardson(About Chris)
  5. 5. @crichardsonAbout Chris()
  6. 6. @crichardsonAbout Chris
  7. 7. @crichardsonAbout Chrishttp://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/
  8. 8. @crichardsonvmc push About-ChrisDeveloper AdvocateSignup at http://cloudfoundry.com
  9. 9. @crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
  10. 10. @crichardsonWhat’s NodeJS?Designed for DIRTy apps
  11. 11. @crichardsonSmall but growing rapidlyBusy!
  12. 12. @crichardsonNodeJS Hello Worldapp.js$ node app.js$ curl http://localhost:1337http://nodejs.org/Load a modulerequest handler
  13. 13. @crichardsonNodeJSJavaScriptReactorpatternModules
  14. 14. @crichardsonNodeJSJavaScriptReactorpatternModules
  15. 15. @crichardsonDynamic, weakly-typedDynamic:Types are associated with values - not variablesDefine new program elements at runtimeWeakly typed:Leave out arguments to methodsAccess non-existent object propertiesWeird implicit conversions: 99 == “99”!truthy and falsy valuesComprehensive tests are essential
  16. 16. @crichardsonJavaScript is object-oriented> var fred = {name: “Fred”, gender: “Male”};undefined> fred.name“Fred”> console.log("reading age=" + fred.age);reading age=undefinedundefined> fred.age = 99;99> fred{ name: Fred,gender: Male,age: 99 }> delete fred.agetrue> fred{ name: Fred, gender: Male }Unordered key-value pairsKeys = propertiesAdd propertyDelete property
  17. 17. @crichardsonJavaScript “classes”function Person(name) {this.name = name;}Person.prototype.sayHello = function () { console.log("Hello " + this.name); };var chris = new Person("Chris");chris.sayHello();Looks like aconstructor?!?What’s that?!?!This Java-like syntax is a messbecause JavaScript isn’t classbasedLooks familiar
  18. 18. @crichardsonoverridesJavaScript is a prototypallanguage__proto__a 99__proto__a 100b 200inheritedPrototypeXY
  19. 19. @crichardsonPrototypal code$ node> var person = {};undefined> person.sayHello = function () { console.log("Hello " + this.name); };[Function]> var chris = Object.create(person, {name: {value: "Chris"}});undefined> var sarah = Object.create(person, {name: {value: "Sarah"}});undefined> chris.sayHello();Hello Chrisundefined> sarah.sayHello();Hello Sarahundefined> chris.sayHello = function () { console.log("Hello mate: " + this.name); };[Function]> chris.sayHello();Hello mate: ChrisundefinedNot definedhereprototype properties
  20. 20. @crichardsonJavaScript is Functionalfunction makeGenerator(nextFunction) {var value = 0;return function() {var current = value;value = nextFunction(value);return current;};}var inc = makeGenerator(function (x) {return x + 1; });> inc()0> inc()1Pass function as anargumentReturn a functionclosure
  21. 21. @crichardsonPartial function application> var join = require("path").join;undefined> join("/x", "y")/x/y> var withinx = join.bind(undefined, "/x");undefined> withinx("y");/x/y>partially apply join
  22. 22. @crichardsonCreated in a hurry with thegoal of looking like JavaThe ‘Java...’ name creates expectations that it can’t satisfyFake classes: Hides prototypes BUT still seems weirdglobal namespacescope of vars is confusingMissing return statement = confusion‘function’ is really verbose‘this’ is dynamically scoped
  23. 23. @crichardsonJavaScript is the only way toget things done in thebrowser
  24. 24. @crichardsonStockholm syndrome“Stockholm syndrome ... is a psychologicalphenomenon in which hostages ... havepositive feelings toward their captors,sometimes to the point of defending them...”http://en.wikipedia.org/wiki/Stockholm_syndrome
  25. 25. @crichardsonMartin Fowler once said:"...Im one of those who despairs that alanguage with such deep flaws plays such animportant role in computation. Still theconsequence of this is that we must takejavascript seriously as a first-class languageand concentrate on how to limit the damageits flaws cause. ...."http://martinfowler.com/bliki/gotoAarhus2012.html
  26. 26. @crichardsonUse just the good parts
  27. 27. @crichardsonUse a better language thatcompiles to JavaScriptTypeScriptTyped parameters and fieldsClasses and interfaces (dynamic structural typing)DartClass-based OOOptional static typingBidirectional binding with DOM elements
  28. 28. @crichardsonCoffeeScript Hello Worldhttp = require(http)class HttpRequestHandlerconstructor: (@message) ->handle: (req, res) =>res.writeHead(200, {Content-Type: text/plain})res.end(@message + n)handler = new HttpRequestHandler "Hi There from CoffeeScript"server = http.createServer(handler.handle)server.listen(1338, 127.0.0.1)console.log(Server running at http://127.0.0.1:1338/)Classes :-)Bound method
  29. 29. @crichardsonNodeJSJavaScriptReactorpatternModules
  30. 30. @crichardsonAbout the Reactor patternDefined by Doug Schmidt in 1995Pattern for writing scalable serversAlternative to thread-per-connection modelSingle threaded event loop dispatches events onhandles (e.g. sockets, file descriptors) to event handlers
  31. 31. @crichardsonReactor pattern structureEvent Handlerhandle_event(type)get_handle()Initiation Dispatcherhandle_events()register_handler(h)select(handlers)for each h in handlersh.handle_event(type)end loophandleSynchronous EventDemultiplexerselect()ownsnotifiesuseshandlers
  32. 32. @crichardsonBenefits:Separation of concerns - event handlers separatedfrom low-level mechanismMore efficient - no thread context switchingSimplified concurrency - single threaded
  33. 33. @crichardsonDrawbacks:Non-pre-emptive - handlers can’t block/take a longtimeDifficult to understand and debug - inverted flow ofcontrol
  34. 34. @crichardsonNodeJS event loop implementsthe Reactor pattern
  35. 35. @crichardsonApplication codeEvent-driven architectureNodeJS event loopBasic networking/file-system/etc.HTTP DB driver ...EventlistenerCallbackfunctionOnetimeeventsRecurringevents
  36. 36. @crichardsonGetting notified: Callbackexamplevar fs = require("fs");function statFile(path) {fs.stat(path, function (err, stat) {if (err) {console.log("Stat failed: " + path, err);throw err;}console.log("stat result=" + path, stat);});};By convention: firstparam is error objectBy convention: Lastarg is a callbackCallbacks aregood for onetimenotifications
  37. 37. @crichardsonGetting notified: eventlistenersEventEmitter class - inherit or useListener registration methods:on(eventName, listener)once(eventName, listener)Emitting eventsemit(eventName, args...)‘error’ event = special case: no listener print stack trace andexit!Good forrecurringevents
  38. 38. @crichardsonEvent listener examplevar fs = require("fs");var readStream = fs.createReadStream("events.js", {encoding: "utf-8"});// ReadStream << ReadableStream << EventEmitterreadStream.on(open, function (fd) {console.log("opened with fd=", fd);});// Node v0.10 has readable instead: this is deprecatedreadStream.on(data, function (data) {console.log("data=", data);});Register listenerRegister listener
  39. 39. @crichardsonCallback hellfunction times2(x, callback) {setTimeout(function () {callback(x * 2)}, 500);}function plus3(x, callback) {setTimeout(function (){callback(x + 3)}, 500);}function displayResult(z) {console.log("The result is=", z);}function plus3AndThenTimes2(x, callback){plus3(x, function (y) {times2(y, callback)})}plus3AndThenTimes2(10, displayResults);function sum(a, b, callback) {setTimeout(function () {callback(a + b);}, 500);}function plus3PlusTimes2(x, callback) {var p3, t2;function perhapsDone() {if (p3 & t2)sum(p3, t2, callback);};plus3(x, function (y) {p3 = y;perhapsDone();});times2(x, function (y) {t2 = y;perhapsDone();});}plus3PlusTimes2(10, displayResult);times2(plus3(x)) times2(x) + plus3(x)
  40. 40. @crichardsonLong running computationsLong running computation blocks event loop forother requestsNeed to run outside of main event loopOptions:Community: web workers threadsBuilt-in: NodeJS child processes
  41. 41. @crichardsonUsing child processesvar child = require(child_process).fork(child.js);function sayHelloToChild() {child.send({hello: "child"});}setTimeout(sayHelloToChild, 1000);child.on(message, function(m) {console.log(parent received:, m);});function kill() {child.kill();}setTimeout(kill, 2000);process.on(message, function (m) {console.log("child received message=", m);process.send({ihateyou: "you ruined my life"})});parent.jschild.jsCreate child processSend message to child
  42. 42. @crichardsonNodeJSJavaScriptReactorpatternModules
  43. 43. Core built-in modulesBasic networkingHTTP(S)FilesystemEventsTimers...
  44. 44. @crichardsonThousands of communitydeveloped moduleshttps://npmjs.org/web frameworks, SQL/NoSQLdatabase, drivers, messaging, utilities...
  45. 45. @crichardsonWhat’s a module?One or more JavaScript filesOptional native code:Compiled during installationJavaScript != systems programming languagePackage.json - metadata including dependenciesexports.sayHello = function () {console.log(“Hello”);}foo.js
  46. 46. @crichardsonEasy to install$ npm install package-name
  47. 47. @crichardsonEasy to usevar http = require(“http”)var server = http.createServer...Core module ORPath to file ORmodule in node_modulesModule’s exports
  48. 48. @crichardsonDeveloping with NodeJSmodulesCore modulesCommunity modulesYour modulesApplication code
  49. 49. @crichardsonLots of modules BUT...Variable qualityMultiple incomplete MySQL drivers, e.g. withoutconnection pooling!Often abandoned...
  50. 50. @crichardsonTo summarizeNodeJSJavaScriptReactor patternModulesFlawed andmisunderstoodScalable yetcostly andoftenunnecessaryRich butvariable quality
  51. 51. @crichardsonAlternative technologiesAtmosphere - portable event deliveryNetty - asynchronous I/OVert.xSpringSource’s Reactor project...
  52. 52. @crichardsonSo why care aboutNodeJS?Easy to write scalable network servicesEasy to push events to the browserEasy to get (small) stuff doneIt has a role to play in modernapplication architecture
  53. 53. @crichardsonEvolving from a monolithicarchitecture....WARShippingServiceAccountingServiceInventoryServiceStoreFrontUI
  54. 54. @crichardson... to a micro-service architectureStore front web applicationshipping web applicationinventory web applicationAccountingServiceStoreFrontUIaccounting web applicationShippingServiceInventoryService
  55. 55. @crichardsonBrowserWARStoreFrontUIModelView ControllerPresentation layer evolution....HTML / HTTP+JavaScript
  56. 56. @crichardsonBrowser Web applicationRESTfulEndpointsModelView Controller...Presentation layer evolutionJSON-RESTHTML 5 -JavaScriptNo elaborate, server-side web frameworkrequiredEventpublisherEventsStaticcontent
  57. 57. @crichardsonNodeJS as an API gatewayBrowserService 1Service 2MessageBusHTML 5/JavaScriptSocket.ioclientEventsRESTful WSServerapplicationSocket.ioserverNode JSService 3RESTfulWS
  58. 58. @crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
  59. 59. @crichardsonServing static content
  60. 60. @crichardsonUsing low-level APIsvar http = require(http), path = require(path), mime = require(mime), fs = require("fs");var server = http.createServer(function (req, res) {var filePath;if (req.url == /) {filePath = public/index.html;} else {filePath = public + req.url;}fs.exists(filePath, function (exists) {if (exists) {res.writeHead(200, {"content-type": mime.lookup(path.basename(filePath)) });fs.createReadStream(filePath).pipe(res);} else {res.writeHead(404, {Content-Type: text/plain});res.write(Error 404: resource not found.);res.end();}});});server.listen(1337, 127.0.0.1);console.log(Server running at http://127.0.0.1:1337/);Uses fileextensionCool!
  61. 61. @crichardsonUsing the express webframeworkvar express = require(express), http = require(http), app = express(), server = http.createServer(app);app.configure(function(){app.use(express.static(__dirname + /public));});server.listen(8081);
  62. 62. @crichardsonRESTful web services
  63. 63. @crichardsonImplementing RESTful WSwith Expressvar express = require(express),http = require(http),path = require(path);var app = express();var server = http.createServer(app);app.get(/portfolio/:userId, function (req, res) {var portfolio = retrievePortfolio(req.params.userId);res.json(portfolio);});Easy URLrouting anddestructuring
  64. 64. @crichardsonProxying to backend serverexpress = require(express)request = require(request)app = express.createServer()proxyToBackend = (baseUrl) ->(req, res) ->callback = (error, response, body) -> console.log("error=", error)originRequest = request(baseUrl + req.url, callback)req.pipe(originRequest)originRequest.pipe(res)app.get(/restaurant/*, proxyToBackend(http://available-restaurant....com))app.post(/orders, proxyToBackend(http://restaurant-management...com))app.get(/orders, proxyToBackend(http://restaurant-management...com))Returns a request handlerthat proxies to baseUrl
  65. 65. @crichardsonDelivering events to thebrowser
  66. 66. @crichardsonNodeJS clock exampleIncrements everysecond
  67. 67. @crichardsonSocket.io - Server sidevar express = require(express), http = require(http), app = express(), server = http.createServer(app), io = require(socket.io).listen(server);app.configure(function(){app.use(express.static(__dirname + /public));});server.listen(8081);io.sockets.on(connection, function (socket) { var counter = 0; function tick() { counter = counter + 1; socket.emit(tick, counter); }; setInterval(tick, 1000);});handle newconnectionSend tick event tobrowser every 1 secinitializes socket.io
  68. 68. @crichardsonSocket.io - client side using theknockout.js MVVM frameworkvar socket = io.connect(location.hostname);function ClockModel() {self.ticker = ko.observable(1);socket.on(tick, function (data) {self.ticker(data);});};ko.applyBindings(new ClockModel());<html><body>The event is <span data-bind="text: ticker"></span><script src="/socket.io/socket.io.js"></script><script src="/knockout-2.0.0.js"></script><script src="/clock.js"></script></body></html>clock.jsConnect tosocket.ioSubscribeto tick eventBind to modelUpdatemodel
  69. 69. @crichardsonDistributed NodeJS clockexampleBrowser NodeJS NodeJSRabbitMQProducerConsumersocket.iosocket.io
  70. 70. @crichardsonAMQP Publishervar amqp = require(amqp),amqpConnection = amqp.createConnection(...),tickTockExchange;function tick() {var message = { tick: Date.now() };tickTockExchange.publish("tickTock", message, {mandatory: true,contentType: "text/plain"});};amqpConnection.on(ready,function () {tickTockExchange =amqpConnection.exchange("tickTock",options = {passive: false, type: fanout});tickTockExchange.on(open, function () { setInterval(tick, 1000) });});Connect toAMQPEnsureexchangeexistsPublishmessageInitialize timer
  71. 71. @crichardsonAMQP socket.iovar express = require(express), http = require(http), amqp = require(‘amqp’)....;server.listen(8081);...var amqpCon = amqp.createConnection(...);io.sockets.on(connection, function (socket) {function amqpMessageHandler(message, headers, deliveryInfo) {var m = JSON.parse(message.data.toString());socket.emit(‘tick’, m);};amqpCon.queue(“”, {},function(queue) {queue.bind(“tickTock”, “”);queue.subscribe(amqpMessageHandler);});});Connect toAMQP queueSubscribe toAMQP queueRepublishas socket.ioeventhttps://github.com/cer/nodejs-clock
  72. 72. @crichardsonAgendaOverview of NodeJSBuilding a front-end server with NodeJSTaming tangled asynchronous code with promises
  73. 73. @crichardsonAsync code = callback hellScenarios:Sequential: A B CFork and join: A and B CCode quickly becomes very messy
  74. 74. @crichardsonSimplifying code withPromises (a.k.a. Futures)Functions return a promise - no callback parameterA promise represents an eventual outcomeUse a library of functions for transforming andcomposing promisesPromises/A+ specification - http://promises-aplus.github.io/promises-specwhen.js (part of cujo.js by SpringSource) is a popularimplementation
  75. 75. @crichardsonTaming callback hell 1function times2(x) {var deferred = when.defer();setTimeout(function () {deferred.resolve(x * 2)}, 500);return deferred.promise;}times2(plus3(x)) Create a deferredReturn a promiseEventually supply a valuefunction plus3AndThenTimes2(x) {return plus3(x).then(times2);}plus3AndThenTimes2(10).then(displayResult);Transform value inpromisefunction plus3(x) {var deferred = when.defer();setTimeout(function () {deferred.resolve(x + 3) }, 500);return deferred.promise;}Simpler, almostsynchronous-style code
  76. 76. @crichardsonTaming callback hell 2function sum(a, b) {var deferred = when.defer();setTimeout(function () {deferred.resolve(a + b);}, 500);return deferred.promise;}function plus3PlusTimes2(x) {var p3 = plus3(x),t2 = times2(x);return when.join(p3, t2).spread(sum);}plus3PlusTimes2(10).then(displayResult);times2(x) + plus3(x)Combine resultsof two promisesCall with arrayelements asarguments
  77. 77. @crichardsonCalling non-promise codevar deferred = when.defer();fs.stat(path, function (err, statInfo) {if (err)deferred.reject(err);elsedeferred.resolve(statInfo);}var promise = deferred.promise;var nodefn = require("when/node/function");var promise = nodefn.call(fs.stat, path)Hidesboilerplatecode
  78. 78. @crichardsonFilesystem scanner exampleRead contents of directoryUse stat to determine if directory or fileRecurse on directoriesMerge the results
  79. 79. @crichardsonRead contents of directoryfunction findFilesInDir(dir) {var directoryContents =nodefn.call(self.fs.readdir, dir);...}Returns promise containingan array of file names
  80. 80. @crichardsonCreate absolute pathsfunction findFilesInDir(dir) {var directoryContents = ...var toAbsolute = join.bind(undefined, dir)var absolutePaths = when.map(directoryContents, toAbsolute);...}Partially applyjoin()
  81. 81. @crichardsonUse stat to determine ifdirectory or filefunction findFilesInDir(dir) {var directoryContents = ...var absolutePaths = ...var statTasks = when.map(absolutePaths, makeStatTask);var statResults = parallel(statTasks);...}function makeStatTask(path) {return function () {function makeStatInfo(stats) {return {path: path, isdir: stats.isDirectory(),ctime: stats.ctime};}return nodefn.call(self.fs.stat, path).then(makeStatInfo);};}Execute stats inparallel
  82. 82. @crichardsonRecurse on directoriesfunction findFilesInDir(dir) {...var statResults = ...;var listOfListsOfFiles =when.map(statResults, processStatInfo);...}function processStatInfo(statInfo) {if (statInfo.isdir) {return findFilesInDir(statInfo.path);} else {return [statInfo.path];}}Map each statresult to a list offiles
  83. 83. @crichardsonFlatten array of arrays of filepathsfunction findFilesInDir(dir) {...var listOfListsOfFiles = ...;return when.reduce(listOfListsOfFiles,concatenateLists, []);}function concatenateLists(currentResult, value, index, total){return currentResult.concat(value);}
  84. 84. @crichardsonSummaryJavaScript is a very flawed languageThe asynchronous model is often unnecessary; veryconstraining; and adds complexityBUT despite those problemsToday, NodeJS is remarkably useful for building network-focussed components
  85. 85. @crichardsonQuestions?@crichardson chris.richardson@springsource.comhttp://plainoldobjects.com - code and slideswww.cloudfoundry.com

×