SlideShare a Scribd company logo
verona
21/05/2011
gabriele lana
gabriele.lana@cleancode.it
  twitter: @gabrielelana
why
         node.js?

“Node's goal is to
  provide an easy
   way to build
scalable network
    programs”

              http://nodejs.org/#about
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
Single thread
synchronous I/0
Single thread
synchronous I/0
multiple thread
synchronous I/0
multiple thread
synchronous I/0
you can
  “always”
 scale with
  multiple
machines but
  it costs
  you $$$
Introduction to Nodejs
but...
what is HE
 doing?
CPU BOUND
          TASKS?


  but...
what is HE
 doing?
CPU BOUND
          TASKS?

             ...OR I/o
  but...       BOUND
what is HE    TASKS?
 doing?
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()
    }
}
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()
    }
}
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()
    }
}
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()
    }
}
single thread
asynchronous I/0
single thread
asynchronous I/0


           I am
       “callback”
         call me
         if you
        need me...
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")
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")
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")
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")
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
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")
                           })
                        })
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)
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
why so
complicated?
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()
                       })
                  })
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
why
                 javascript?


•   Friendly callbacks
•   ubiquitous (well known)
•   no I/o primitives
•   one language to rule them all
web applications
                             before: a web
mind shift #1               server with some
                            application logic


                        application
           Web server

                        application


                        application


                        application
web applications
                        after: an application
mind shift #1             accessible over
                                http
        web server




                     application
web applications
                        after: an application
mind shift #1                 that can
                          communicate and
                         collaborate with
                             the world
        web server




                     application
web applications
                    before: stateful
mind shift #2   • no easy to scale
                • no easy to reuse

                v
                     M
                c
web applications
                    before: stateful
mind shift #2   • no easy to scale
                • no easy to reuse

                v
                     M
                c


  conversation       application
     state             state
web applications
                    before: stateful
mind shift #2   • no easy to scale
                • no easy to reuse

                v
                     M
                c



   tightly coupled
web applications
                    after: stateless
mind shift #2      • easy to scale
                   • easy to reuse


       v
            http
                       M
       c
web applications
                    after: stateless
mind shift #2      • easy to scale
                   • easy to reuse


       v
            http
                       M
       c


conversation       application
   state             state
web applications
                       after: stateless
mind shift #2
                http




                       web server
                                        M
                http

                                     statefull
                                    connection



• easy to scale                                  M
• easy to reuse
no fluff
just stuff
What about
cpu bound
  tasks?
the fork
long_running_job.sh                          be with you



                      #!/bin/bash

                      for count in `seq 1 100`; do
                           echo $count
                           sleep 0.1
                      done
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()
                              })
                         })
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
...
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
...
enter comet

w
 at
   ch
watch          M                spawn
   ch
 at
w




               watch
           w




                       w
        t a




                       at
          ch




                           ch
enter comet




demo
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
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})
                     )
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})
                             })
                          })
                     })
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]
                          })

                     })
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()
                     })
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>
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>
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()
                            })
                         })
                     }
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
              }
we can do it
with a little
more “style”
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
                     })()
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")
                     })
node.js is
 awesome
 but when
 should i
  use it?
when to use it?

•   chat/messaging
•   real-time applications
•   intelligent proxies
•   high concurrency applications
•   communication hubs
•   coordinators
please tell
me something
 bad about
  node.js
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
vs
Introduction to Nodejs
Introduction to Nodejs
Questions?
gabriele lana
   gabriele.lana@cleancode.it
     twitter: @gabrielelana

http://joind.in/3359

More Related Content

Introduction to Nodejs

  • 3. why node.js? “Node's goal is to provide an easy way to build scalable network programs” http://nodejs.org/#about
  • 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
  • 9. you can “always” scale with multiple machines but it costs you $$$
  • 12. CPU BOUND TASKS? but... what is HE doing?
  • 13. CPU BOUND TASKS? ...OR I/o but... BOUND what is HE TASKS? doing?
  • 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. 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. 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. 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() } }
  • 19. single thread asynchronous I/0 I am “callback” call me if you need me...
  • 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. 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. 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. 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")
  • 24. 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
  • 25. 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") }) })
  • 26. 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)
  • 27. 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
  • 29. 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() }) })
  • 30. 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
  • 31. why javascript? • Friendly callbacks • ubiquitous (well known) • no I/o primitives • one language to rule them all
  • 32. web applications before: a web mind shift #1 server with some application logic application Web server application application application
  • 33. web applications after: an application mind shift #1 accessible over http web server application
  • 34. web applications after: an application mind shift #1 that can communicate and collaborate with the world web server application
  • 35. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c
  • 36. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c conversation application state state
  • 37. web applications before: stateful mind shift #2 • no easy to scale • no easy to reuse v M c tightly coupled
  • 38. web applications after: stateless mind shift #2 • easy to scale • easy to reuse v http M c
  • 39. web applications after: stateless mind shift #2 • easy to scale • easy to reuse v http M c conversation application state state
  • 40. web applications after: stateless mind shift #2 http web server M http statefull connection • easy to scale M • easy to reuse
  • 43. the fork long_running_job.sh be with you #!/bin/bash for count in `seq 1 100`; do echo $count sleep 0.1 done
  • 44. 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() }) })
  • 45. 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 ...
  • 46. 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 ...
  • 47. enter comet w at ch watch M spawn ch at w watch w w t a at ch ch
  • 49. 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
  • 50. 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}) )
  • 51. 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}) }) }) })
  • 52. 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] }) })
  • 53. 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() })
  • 54. 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>
  • 55. 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>
  • 56. 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() }) }) }
  • 57. 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 }
  • 58. we can do it with a little more “style”
  • 59. 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 })()
  • 60. 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") })
  • 61. node.js is awesome but when should i use it?
  • 62. when to use it? • chat/messaging • real-time applications • intelligent proxies • high concurrency applications • communication hubs • coordinators
  • 63. please tell me something bad about node.js
  • 64. 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
  • 65. vs
  • 69. gabriele lana gabriele.lana@cleancode.it twitter: @gabrielelana http://joind.in/3359