Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
Introduction to Node.js
Introduction to Node.js
Loading in …3
×
1 of 69

Introduction to Nodejs

36

Share

Download to read offline

Introduction to Nodejs with examples

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Introduction to Nodejs

  1. 1. verona 21/05/2011
  2. 2. gabriele lana gabriele.lana@cleancode.it twitter: @gabrielelana
  3. 3. why node.js? “Node's goal is to provide an easy way to build scalable network programs” http://nodejs.org/#about
  4. 4. what is node.js? • asynchronous i/o framework • core in c++ on top of v8 • rest of it in javascript • swiss army knife for network related stuffs • can handle thousands of concurrent connections with minimal overhead (cpu/memory) on a single process
  5. 5. Single thread synchronous I/0
  6. 6. Single thread synchronous I/0
  7. 7. multiple thread synchronous I/0
  8. 8. multiple thread synchronous I/0
  9. 9. you can “always” scale with multiple machines but it costs you $$$
  10. 10. but... what is HE doing?
  11. 11. CPU BOUND TASKS? but... what is HE doing?
  12. 12. CPU BOUND TASKS? ...OR I/o but... BOUND what is HE TASKS? doing?
  13. 13. synchronous I/0 function productsInCart(request, response) { var db = new Db() var user = new User(request) if (user.isAuthorized("cart/products")) { response.write( JSON.stringify( db.productsInCart(user.cartId()) ) ) } else { response.unauthorized() } }
  14. 14. synchronous I/0 function productsInCart(request, response) { var db = new Db() var user = new User(request) if (user.isAuthorized("cart/products")) { response.write( JSON.stringify( db.productsInCart(user.cartId()) ) ) } else { response.unauthorized() } }
  15. 15. synchronous I/0 function productsInCart(request, response) { var db = new Db() var user = new User(request) if (user.isAuthorized("cart/products")) { response.write( JSON.stringify( db.productsInCart(user.cartId()) ) ) } else { response.unauthorized() } }
  16. 16. synchronous I/0 function productsInCart(request, response) { var db = new Db() var user = new User(request) if (user.isAuthorized("cart/products")) { response.write( JSON.stringify( db.productsInCart(user.cartId()) ) ) } else { response.unauthorized() } }
  17. 17. single thread asynchronous I/0
  18. 18. single thread asynchronous I/0 I am “callback” call me if you need me...
  19. 19. hello_world_server.js Event Emitter var http = require("http") var server = http.createServer(function(request, response) { response.writeHead(200, { "Content-Type": "plain/text" }) response.write("Hello Worldn") response.end() }) server.listen(8080) console.log("> SERVER STARTED")
  20. 20. hello_world_server.js Event Emitter var http = require("http") var server = http.createServer(function(request, response) { response.writeHead(200, { "Content-Type": "plain/text" }) response.write("Hello Worldn") response.end() }) server.listen(8080) console.log("> SERVER STARTED")
  21. 21. hello_world_server.js Event Emitter var http = require("http") var server = http.createServer(function(request, response) { response.writeHead(200, { "Content-Type": "plain/text" }) response.write("Hello Worldn") response.end() }) server.listen(8080) console.log("> SERVER STARTED")
  22. 22. hello_world_server.js Event Emitter var http = require("http") var server = http.createServer(function(request, response) { response.writeHead(200, { "Content-Type": "plain/text" }) response.write("Hello Worldn") response.end() }) server.listen(8080) console.log("> SERVER STARTED")
  23. 23. Event Emitter coder@apollo:~/Work/src/node/examples$ node hello_world_server.js > SERVER STARTED #1 coder@apollo:~$ curl "http://localhost:8080/" Hello World #2
  24. 24. Event Emitter var server = require("http").createServer() hello_world_server.js server.on("request", function(request, response) { console.log("> REQUEST STARTED") request.on("end", function() { console.log("> REQUEST CLOSED") response.writeHead(200, { "Content-Type": "plain/text" }) response.end("Hello Worldn") server.close() }) response.on("close", function() { console.log("> RESPONSE CLOSED") }) })
  25. 25. hello_world_server.js Event Emitter ... server.on("close", function() { console.log("> SERVER CLOSED") }) server.on("listening", function() { console.log("> SERVER STARTED") }) server.listen(8080)
  26. 26. Event Emitter coder@apollo:~/Work/src/node/examples$ node hello_world_server.js > SERVER STARTED #1 coder@apollo:~$ curl "http://localhost:8080/" Hello World #2 #1 > REQUEST STARTED > REQUEST CLOSED > SERVER CLOSED
  27. 27. why so complicated?
  28. 28. data streamS server.on("request", function(request, response) { var chunks = [], output = fs.createWriteStream("./output") proxy_stream.js request.on("data", function(chunk) { chunks = forEachLine(chunks.concat(chunk), function(line) { output.write(parseInt(line, 10) * 2) output.write("n") }) }) request.on("end", function() { response.writeHead(200, { "Content-Type": "plain/text" }) response.end("OKn") output.end() server.close() }) })
  29. 29. data streamS coder@apollo:~/Work/src/node/examples$ node stream_doubler.js #1 coder@apollo:~$ curl "http://localhost:8080/" --data $'1n2n3n' OK #2 coder@apollo:~/Work/src/node/examples$ cat output 2 4 6 #1
  30. 30. why javascript? • Friendly callbacks • ubiquitous (well known) • no I/o primitives • one language to rule them all
  31. 31. web applications before: a web mind shift #1 server with some application logic application Web server application application application
  32. 32. web applications after: an application mind shift #1 accessible over http web server application
  33. 33. web applications after: an application mind shift #1 that can communicate and collaborate with the world web server application
  34. 34. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c
  35. 35. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c conversation application state state
  36. 36. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c tightly coupled
  37. 37. web applications after: stateless mind shift #2 • easy to scale • easy to reuse v http M c
  38. 38. web applications after: stateless mind shift #2 • easy to scale • easy to reuse v http M c conversation application state state
  39. 39. web applications after: stateless mind shift #2 http web server M http statefull connection • easy to scale M • easy to reuse
  40. 40. no fluff just stuff
  41. 41. What about cpu bound tasks?
  42. 42. the fork long_running_job.sh be with you #!/bin/bash for count in `seq 1 100`; do echo $count sleep 0.1 done
  43. 43. the fork long_running_server.js be with you var spawn = require("child_process").spawn, server = require("http").createServer() server.on("request", function(request, response) { var job = spawn("./long_running_job.sh") job.stdout.on("data", function(tick) { response.write(tick) }) job.on("exit", function() { response.end() }) })
  44. 44. the fork be with you coder@apollo:~$ ab -c 1 -n 1 "http://localhost:8080/" ... Concurrency Level: 1 Time taken for tests: 10.531 seconds ... coder@apollo:~$ ab -c 1 -n 2 "http://localhost:8080/" ... Concurrency Level: 1 Time taken for tests: 20.108 seconds ...
  45. 45. the fork be with you coder@apollo:~$ ab -c 2 -n 1 "http://localhost:8080/" ... Concurrency Level: 2 Time taken for tests: 10.634 seconds ... coder@apollo:~$ ab -c 100 -n 100 "http://localhost:8080/" ... Concurrency Level: 100 Time taken for tests: 11.198 seconds ... coder@apollo:~$ ab -c 500 -n 500 "http://localhost:8080/" ... Concurrency Level: 500 Time taken for tests: 31.082 seconds ...
  46. 46. enter comet w at ch watch M spawn ch at w watch w w t a at ch ch
  47. 47. enter comet demo
  48. 48. INSTALL NPM (node packet manager) coder@apollo:~/Work/src/node/examples$ curl http://npmjs.org/install.sh | sh ... npm ok It worked coder@apollo:~/Work/src/node/examples$ npm search | wc -l 1918 coder@apollo:~/Work/src/node/examples$ npm install connect socket.io underscore coder@apollo:~/Work/src/node/examples$ npm list !"# connect@1.4.1 $ !"" mime@1.2.2 $ %"" qs@0.1.0 %"" socket.io@0.6.17 %"" underscore@1.1.6
  49. 49. server/ routing progress_server.js var server = connect( connect.favicon(), connect.logger({"buffer": true}), connect.router(function(resource) { resource.post("/spawn", function(request, response) { ... }) }), connect.static(path.join(__dirname, "public"), {"cache": true}) )
  50. 50. server/ routing progress_server.js resource.post("/spawn", function(request, response) { var job = spawn(path.join(__dirname, "bin", "job.sh")), id = ++counter response.writeHead(202, {"Content-Type": "plain/text"}) response.end("OKn") job.stdout.on("data", function(output) { var progress = parseInt(output.toString(), 10) _(connections).each(function(connection) { connection.send({"id": id, "progress": progress}) }) }) })
  51. 51. server/ socket.io progress_server.js io.listen(server).on("connection", function(client) { connections[client.sessionId] = client client.on("disconnect", function() { delete connections[client.sessionId] }) })
  52. 52. server/ simulation progress_server.js server.listen(port, host, function() { var spawnJobsInterval = setInterval(function() { http.request({ "port": port, "host": host, "method": "POST", "path": "/spawn" }).end() }, Math.floor(Math.random()*2000)+500) server.on("close", function() { clearInterval(spawnJobsInterval) process.exit() }) }) process.on("SIGINT", function() { server.close() })
  53. 53. interface/html <html> <head> <title>Node.js - Long Running Jobs</title> <link href="css/style.css" rel="stylesheet" /> <script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript" src="js/jquery-1.6.0.js"></script> <script type="text/javascript" src="js/progress.js"></script> index.html </head> <body> <div id="template"> <div class="progress-container"> <span class="progress-text">JOB/? - ?%</span> <div class="progress-bar"></div> </div> </div> <div id="container"> </div> </body> <script> ... </script> </html>
  54. 54. interface/ socket.io <html> ... <script> $(function() { var socket = new io.Socket() index.html socket.on("connect", function() { }) socket.on("disconnect", function() { }) socket.on("message", function(job) { $("#template").progressBar(job.id, job.progress) }) socket.connect() }) </script> </html>
  55. 55. interface/ progress bar $.fn.progressBar = function(id, progress) { var $template = $(this) $("#job-" + id) .otherwise(function() { return $template.children().clone() progress.js .attr("id", "job-" + id) .find(".progress-text").text("JOB/" + id + " - 0%").end() .appendTo("#container") }) .find(".progress-text").text("JOB/" + id + " - " + progress + "%").end() .find(".progress-bar").css("width", progress + "%").end() .tap(function() { if (progress === 100) { $(this) .find(".progress-bar").css("background-color", "red").end() .after(500, function() { $(this).fadeOut("slow", function() { $(this).remove() }) }) }
  56. 56. interface/ progress bar $.fn.otherwise = function(ifNotFound) { if (this.length === 0) { return ifNotFound() } progress.js return this } $.fn.after = function(milliseconds, doSomething) { var self = this setTimeout(function() { doSomething.apply(self) }, milliseconds) return this } $.fn.tap = function() { var fn = Array.prototype.shift.apply(arguments) fn.apply(this, arguments) return this }
  57. 57. we can do it with a little more “style”
  58. 58. server/ event emitter var Job = (function() { var EventEmitter = require("events").EventEmitter, progress_server.js spawn = require("child_process").spawn, inherits = require("util").inherits function Job(id) { EventEmitter.call(this) this.id = id } inherits(Job, EventEmitter) Job.prototype.run = function() { return _(this).tap(function(job) { spawn(path.join(__dirname, "bin", "job.sh")) .stdout.on("data", function(output) { job.emit("progress", job.id, parseInt(output.toString(), 10)) }) }) } return Job })()
  59. 59. server/ event emitter progress_server.js resource.post("/spawn", function(request, response) { new Job(++counter) .on("progress", function(id, progress) { _(connections).each(function(connection) { connection.send({"id": id, "progress": progress}) }) }) .run() response.writeHead(202, { "Content-Type": "plain/text" }) response.end("OKn") })
  60. 60. node.js is awesome but when should i use it?
  61. 61. when to use it? • chat/messaging • real-time applications • intelligent proxies • high concurrency applications • communication hubs • coordinators
  62. 62. please tell me something bad about node.js
  63. 63. some warnings • release stable 0.4.7 (young) • lots of stuffs to look at • lots of half backed stuffs • retro compatibility??? • bad at handling static contents • Bad at handling binary contents • hard to find organized and authoritative informations
  64. 64. vs
  65. 65. Questions?
  66. 66. gabriele lana gabriele.lana@cleancode.it twitter: @gabrielelana http://joind.in/3359

×