Introduction to Nodejs

19,325 views
19,153 views

Published on

Introduction to Nodejs with examples

Published in: Technology
0 Comments
29 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
19,325
On SlideShare
0
From Embeds
0
Number of Embeds
4,379
Actions
Shares
0
Downloads
699
Comments
0
Likes
29
Embeds 0
No embeds

No notes for slide

Introduction to Nodejs

  1. 1. verona21/05/2011
  2. 2. gabriele lanagabriele.lana@cleancode.it twitter: @gabrielelana
  3. 3. why node.js?“Nodes goal is to provide an easy way to buildscalable 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 threadsynchronous I/0
  6. 6. Single threadsynchronous I/0
  7. 7. multiple threadsynchronous I/0
  8. 8. multiple threadsynchronous I/0
  9. 9. you can “always” scale with multiplemachines 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... BOUNDwhat is HE TASKS? doing?
  13. 13. synchronous I/0function 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/0function 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/0function 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/0function 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 threadasynchronous I/0
  18. 18. single threadasynchronous 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 Emittercoder@apollo:~/Work/src/node/examples$ node hello_world_server.js> SERVER STARTED #1coder@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 Emittercoder@apollo:~/Work/src/node/examples$ node hello_world_server.js> SERVER STARTED #1coder@apollo:~$ curl "http://localhost:8080/"Hello World #2 #1> REQUEST STARTED> REQUEST CLOSED> SERVER CLOSED
  27. 27. why socomplicated?
  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 streamScoder@apollo:~/Work/src/node/examples$ node stream_doubler.js #1coder@apollo:~$ curl "http://localhost:8080/" --data $1n2n3nOK #2coder@apollo:~/Work/src/node/examples$ cat output246 #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 webmind shift #1 server with some application logic application Web server application application application
  32. 32. web applications after: an applicationmind shift #1 accessible over http web server application
  33. 33. web applications after: an applicationmind shift #1 that can communicate and collaborate with the world web server application
  34. 34. web applications before: statefulmind shift #2 • no easy to scale • no easy to reuse v M c
  35. 35. web applications before: statefulmind shift #2 • no easy to scale • no easy to reuse v M c conversation application state state
  36. 36. web applications before: statefulmind shift #2 • no easy to scale • no easy to reuse v M c tightly coupled
  37. 37. web applications after: statelessmind shift #2 • easy to scale • easy to reuse v http M c
  38. 38. web applications after: statelessmind shift #2 • easy to scale • easy to reuse v http M cconversation application state state
  39. 39. web applications after: statelessmind shift #2 http web server M http statefull connection• easy to scale M• easy to reuse
  40. 40. no fluffjust stuff
  41. 41. What aboutcpu bound tasks?
  42. 42. the forklong_running_job.sh be with you #!/bin/bash for count in `seq 1 100`; do echo $count sleep 0.1 done
  43. 43. the forklong_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 youcoder@apollo:~$ ab -c 1 -n 1 "http://localhost:8080/"...Concurrency Level: 1Time taken for tests: 10.531 seconds...coder@apollo:~$ ab -c 1 -n 2 "http://localhost:8080/"...Concurrency Level: 1Time taken for tests: 20.108 seconds...
  45. 45. the fork be with youcoder@apollo:~$ ab -c 2 -n 1 "http://localhost:8080/"...Concurrency Level: 2Time taken for tests: 10.634 seconds...coder@apollo:~$ ab -c 100 -n 100 "http://localhost:8080/"...Concurrency Level: 100Time taken for tests: 11.198 seconds...coder@apollo:~$ ab -c 500 -n 500 "http://localhost:8080/"...Concurrency Level: 500Time taken for tests: 31.082 seconds...
  46. 46. enter cometw at chwatch M spawn ch atw watch w w t a at ch ch
  47. 47. enter cometdemo
  48. 48. INSTALL NPM (node packet manager)coder@apollo:~/Work/src/node/examples$ curl http://npmjs.org/install.sh | sh...npm okIt workedcoder@apollo:~/Work/src/node/examples$ npm search | wc -l1918coder@apollo:~/Work/src/node/examples$ npm install connect socket.io underscorecoder@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/ routingprogress_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/ routingprogress_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.ioprogress_server.js io.listen(server).on("connection", function(client) { connections[client.sessionId] = client client.on("disconnect", function() { delete connections[client.sessionId] }) })
  52. 52. server/ simulationprogress_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 itwith a littlemore “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 emitterprogress_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 tellme 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: @gabrielelanahttp://joind.in/3359

×