sY Ptoc 1t!xt!/ 2 8 8 8 9 9 9 10 10 10 10 10 12 12 12 12 12 12 12 12 12 13 13 13 13 13 13 13 13 13 13 14 14 14 14 15 15 15 16 17 18 19 20 22 22 22 23 TabIe of Content Table of Content Credits About this book Acknowledgements ntroduction Why the sudden, exponential popularity? What does this book cover? What does this book not cover? Prerequisites Exercises Source code Where will this book lead you? Chapter Overview Why? Starting up Understanding Basics AP Quick Tour Utilities Buffers Event Emitter Timers Low-level File System HTTP Streams TCP Server UNX Sockets Datagrams (UDP) Child Processes Streaming HTTP Chunked Responses TLS / SSL HTTPS Making Modules Debugging Automated Unit Testing Callback Flow Why? Why the event loop? Solution 1: Create more call stacks Solution 2: Use event callbacks Why Javascript? How Learned to Stop Fearing and Love Javascript Function Declaration Styles Functions are first-class objects JSLint Javascript versions Handling callbacks References Table of Content Table of Content 2/147 25 25 26 26 27 27 28 28 29 29 29 30 30 31 32 32 32 32 32 32 34 34 34 34 34 34 34 35 35 35 35 35 35 35 36 36 37 39 39 40 40 40 40 40 42 42 42 43 43 44 44 44 45 45 45 Starting up nstall Node NPM - Node Package Manager NPM commands npm ls [filter] npm install package[@filters] npm rm package_name[@version] [package_name[@version] ...] npm view [@] [[.]...] Understanding Understanding the Node event loop An event-queue processing loop Callbacks that will generate events Don't block! Understanding Modules How Node resolves a module path Core modules Modules with complete or relative path As a file As a directory As an installed module AP quick tour Processes process child_process File system fs path Networking net dgram http tls (ssl) https dns Utilities console util Buffers Slice a buffer Copy a buffer Buffer Exercises Exercise 1 Exercise 2 Exercise 3 Event Emitter .addListener .once .removeAllListeners Creating an Event Emitter Event Emitter Exercises Exercise 1 Exercise 2 Timers setTimeout clearTimeout Table of Content Table of Content 3/147 46 46 46 47 48 49 49 50 51 51 52 53 55 55 55 55 55 55 56 57 57 58 58 58 58 59 59 59 60 60 60 60 61 62 62 62 63 63 64 64 64 64 65 65 65 65 66 66 66 67 67 67 68 68 70 70 70 72 setnterval clearnterval process.nextTick Escaping the event loop A note on tail recursion Low-level file-system fs.stat and fs.fstat Open a file Read from a file Write into a file Close Your files Advanced Tip: careful when appending concurrently File-system Exercises Exercise 1 - get the size of a file Exercise 2 - read a chunk from a file Exercise 3 - read two chunks from a file Exercise 4 - Overwrite a file Exercise 5 - append to a file Exercise 6 - change the content of a file HTTP HTTP Server The http.ServerRequest object req.url req.method req.headers The http.ServerResponse object Write a header Change or set a header Remove a header Write a piece of the response body HTTP Client http.get() http.request() HTTP Exercises Exercise 1 Exercise 2 Exercise 3 Exercise 4 Streams, pump and pipe ReadStream Wait for data Know when it ends Pause it Resume it WriteStream Write Wait for it to drain Some stream examples Filesystem streams Network streams The Slow Client Problem What can we do? Pump ... and his cousin "pipe" Making your own ReadStream WriteStream TCP Table of Content Table of Content 4/147 72 73 73 73 74 74 74 74 75 76 76 76 76 78 78 78 78 79 80 82 82 83 84 85 85 86 86 86 87 87 88 88 89 89 90 90 91 91 92 92 92 92 93 93 94 94 94 94 94 95 95 Write a string or a buffer end ...and all the other methods dle sockets Keep-alive Delay or no delay server.close() Listening TCP client Error handling TCP Exercises Exercise 1 Exercise 2 UNX sockets Server Client Passing file descriptors around Read or write into that file Listen to the server socket Datagrams (UDP) Datagram server Datagram client Datagram Multicast Receiving multicast messages Sending multicast messages What can be the datagram maximum size? UDP Exercises Exercise 1 Child processes Executing commands Spawning processes Killing processes Child Processes Exercises Exercise 1 Streaming HTTP chunked responses A streaming example Streaming Exercises Exercise 1 TLS / SSL Public / private keys Private key Public key TLS Client TLS Server Verification TLS Exercises Exercise 1 Exercise 2 Exercise 3 Exercise 4 Exercise 5 Table of Content Table of Content 5/147 96 96 96 98 98 98 99 100 100 101 102 103 103 103 104 107 108 108 109 109 109 110 110 110 110 110 110 110 110 110 110 110 111 111 111 111 111 111 111 113 114 116 118 120 120 120 120 121 121 122 122 123 123 123 124 124 125 125 125 HTTPS HTTPS Server HTTPS Client Making modules CommonJS modules One file module An aggregating module A pseudo-class A pseudo-class that inherits node_modules and npm bundle Bundling Debugging console.log Node built-in debugger Node nspector Live edit Automated Unit Testing A test runner Assertion testing module should.js Assert truthfulness: or untruthfulness: === true === false emptiness equality equal (strict equality) assert numeric range (inclusive) with within test numeric value is above given value: test numeric value is below given value: matching rec+gular expressions test length substring inclusion assert typeof property existence array containment own object keys responds to, asserting that a given property is a function: Putting it all together Callback flow The boomerang effect Step Parallel execution Appendix - Exercise Results Chapter: Buffers Exercise 1 One solution: Exercise 2 One solution: Exercise 3 One Solution: Chapter: Event Emitter Exercise 1 One solution: Exercise 2 One solution: Chapter: Low-level File System Exercise 1 - get the size of a file One solution Table of Content Table of Content 6/147 126 126 127 127 128 128 129 129 130 130 131 131 131 132 132 133 133 134 134 135 135 135 137 137 137 138 138 138 139 139 139 140 140 141 141 141 144 144 145 145 146 146 147 147 Exercise 2 - read a chunk from a file One solution Exercise 3 - read two chunks from a file One solution Exercise 4 - Overwrite a file One solution: Exercise 5 - append to a file One Solution: Exercise 6 - change the content of a file One solution: Chapter: HTTP Exercise 1 One solution: Exercise 2 One solution: Exercise 3 One solution: Exercise 4 One solution: Chapter: Child processes Exercise 1 One solution: Chapter: Streaming HTTP Chunked responses Exercise 1 One solution: Chapter: UDP Exercise 1 One solution: Chapter: TCP Exercise 1 One solution: Exercise 2 One solution: Chapter: SSL / TLS Exercise 1 One solution: Exercise 2 One solution: Exercise 3 One solution: Exercise 4 One solution: Exercise 5 One solution: Table of Content Table of Content 7/147 Cred|ts This secono revision ol this book coulo not have been oone without the the help ol Timothv Kevin Oxlev. who co-revieweo eno eoiteo most ol this book. About th|s book This book was built using Nooe.js. Express. the ]aoe templating engine. wkhtmltopol. bash scripts. git ano github. Version: 1.1 Acknow|edgements I'm gratelul to mv oear wile Susana lor putting up with mv mooo swings about this book. to mv Iather lor teaching me how to program Basic on a ZX Spectrum when I was 10 vears olo. to mv Farents ano mv Granomother Maria oo Carmo lor ollering me mv nrst IBM FC clone a little later ano to mv lrieno Feoro Menoes who gave me the ioea lor making this book. Hands-on Node Credits 8/147 Introduct|on At the European ]SConl 2009. a voung programmer bv the name ol Rvan Dahl. introouceo a project he hao been working on. This project was a platlorm that combining Google's V8 ]avascript engine ano an event loop. The project then took a oillerent oirection lrom other server-sioe ]avascript platlorms: all IO primitives were event-oriven. ano there was no wav arouno it. Leveraging the power ano simplicitv ol ]avascript. it turneo the oilncult task ol writing asvnchronous applications into an easv one. Since receiving a stanoing ovation at the eno ol his talk. Dahl's project has been met with unpreceoenteo growth. popularitv ano aooption. The project was nameo Nooe.js. now known to oevelopers simplv as 'Nooe'. Nooe provioes purelv eventeo. non-blocking inlrastructure lor builoing highlv concurrent soltware. Nooe allows vou to easilv construct last ano scalable network services. Why the sudden, exponent|a| popu|ar|ty? Server-sioe ]avascript has been arouno lor some time. what makes this platlorm so appealing? In previous server-sioe ]avascript implementations. javascript was the raison o'etre. ano the approach locusseo on translating common practices lrom other platlorms like Rubv. FERL ano Fvthon. into ]avascript. Nooe takes a leap lrom this ano savs: "Let's use the successlul event-oriven programming mooel ol the web ano use it to make an easv wav to builo scalable servers. Ano let's make it the onlv wav people can oo anvthing on this platlorm.". It can be argueo that ]avascript itsell contributeo to much ol Nooe's success. but that woulo not explain whv other the server-sioe projects proceeoing Nooe have not vet come close in popularitv. The ubiquitv ol ]avascript surelv has plaveo a role. but. as Rvan Dahl points out. unlike other SS]S attempts. a unilving clientserver language was not the primarv goal lor Nooe. In the perspective ol this author. there are three lactors contributing to Nooe's success: 1. Nooe is Easv - Nooe makes event-oriven IO programming. the best wav to oo IO programming. much easier to unoerstano ano achieve than ever belore. 2. Nooe is Lean - Nooe ooes not trv to solve all problems. It lavs the lounoation ano supports the basic internet protocols using clean. lunctional AFIs. 3. Nooe ooes not Compromise - Nooe ooes not trv to be compatible with pre-existing soltware. it takes a lresh look at what manv believe is the right oirection. What does th|s book cover? Hands-on Node ntroduction 9/147 We will analvze what makes Nooe a oillerent proposal to other server-sioe solutions. whv vou shoulo use it. ano how to get starteo. We will start with an overview but quicklv oive into some cooe mooule- bv-mooule. Bv the eno ol this book vou shoulo be able to builo ano test vour own Nooe mooules. service prooucersconsumers ano leel comlortable using Nooe's conventions ano AFI. What does th|s book not cover? This book ooes not attempt to cover the complete Nooe AFI. Insteao. we will cover what the author thinks is requireo to builo most applications he woulo builo on Nooe. This book ooes not cover anv Nooe lrameworks. Nooe is a great tool lor builoing lrameworks ano manv are available. such as cluster management. inter-process communication. web lrameworks. network tralnc collection tools. game engines ano manv others. Belore vou oive into anv ol those vou shoulo be lamiliar with Nooe's inlrastructure ano what it provioes to these builoing blocks. Prerequ|s|tes This book ooes not assume vou have anv prior knowleoge ol Nooe. but the cooe examples are written in ]avascript. so lamiliaritv with the ]avascript language will help. Exerc|ses This book has exercises in some chapters. At the eno ol this book vou can nno the exercise solutions. but I aovise vou to trv oo them voursell. Consult this book or use the comprehensive AFI oocumentation on the olncial http:nooejs.org website. Source code You can nno some ol the source cooe ano exercises useo in this book on GitHub: https:github.compgtehanoson_nooejs_source_cooe or vou can oownloao it oirectlv: https:github.compgtehanoson_nooejs_source_cooezipballmaster Where w||| th|s book |ead you? Bv the eno ol it. vou shoulo unoerstano the Nooe AFI ano be able to pursue the exploration ol other things built on top ol it. being aoaptors. lrameworks ano mooules. Let's get starteo Hands-on Node ntroduction 10/147 Hands-on Node ntroduction 11/147 Chapter Overv|ew While this book ooes not neeo to be reao lrom cover to cover. it will help since some common concepts presenteo earlier in the book will probablv not be repeateo. Why? Whv ooes Nooe use event-oriven programming ano ]avascript together? Whv is ]avascript a great language? Start|ng up How to install Nooe ano get Nooe mooules using NFM. Understand|ng Bas|cs How Nooe loaos mooules. how the Event Loop lunctions ano what to look out lor in oroer not to block it. API Qu|ck Tour Quick overview ol Nooe's core mooules. Ut|||t|es Uselul Nooe utilities. Buffers Learn to create. mooilv ano access buller oata. an essential part ol the Nooe lunoamentals. Event Em|tter How the Event Emitter pattern is useo throughout Nooe ano how to use it lor nexibilitv in vour cooe. T|mers Hands-on Node Chapter Overview 12/147 Nooe's timer AFI. reminiscent ol browsers. Low-|eve| F||e System How to use Nooe to open. reao ano write nles. HTTP Nooe's rich HTTF server ano client implementation. Streams The richness ol this great abstraction in Nooe. TCP Server Quicklv setup a bare TCF server. UNIX Sockets How to use UNIX sockets ano use them to pass nle oescriptors arouno. Datagrams (UDPj The power ol oatagrams in Nooe Ch||d Processes Launching. watching. piping ano killing other processes. Stream|ng HTTP Chunked Responses HTTF in Nooe is streamable lrom the get go. TLS / SSL How to provioe ano consume secure streams. HTTPS Hands-on Node Chapter Overview 13/147 How to builo a secure HTTFS server or client. Mak|ng Modu|es How to make vour app more mooular. Debugg|ng How to oebug vour Nooe app. Automated Un|t Test|ng How to unit test vour mooules. Ca||back F|ow How to manage intricate callback now in a sane wav. Hands-on Node Chapter Overview 14/147 Why? Why the event |oop? The Event Loop is a soltware pattern that lacilitates non-blocking IO network. nle or inter-process communication. Traoitional blocking programming ooes IO in the same lashion as regular lunction calls. processing mav not continue until the operation is complete. Here is some pseuoo-cooe that oemonstrates blocking IO: l. var post = db.querv{`SELECT * FROM posts where id = l`}; 2. // processing from this line onward cannot execute until the line above completes 3. doSomethingWithPost{post}; 4. doSomethingElse{}; What is happening here? While the oatabase querv is being executeo. the whole processthreao ioles. waiting lor the response. This is calleo blocking. The response to this querv mav take manv thousanos ol CFU cvcles. renoering the entire process unusable ouring this time. The process coulo have been servicing other client requests insteao ol just waiting. This ooes not allow vou to parallelize IO such as perlorming another oatabase querv or communicating with a remote web service. without involving concurrent programming trickerv. The call stack becomes lrozen. waiting lor the oatabase server to replv. This leaves vou with two possible solutions to keep the process busv while it's waiting: create more call stacks or use event callbacks. So|ut|on 1: Create more ca|| stacks In oroer lor vour process to hanole more concurrent IO. vou have to have more concurrent call stacks. Ior this. vou can use threaos or some kino ol cooperative multi-threaoing scheme like co- routines. nbers. continuations. etc. The multi-threaoeo concurrencv mooel can be verv oilncult to conngure. unoerstano ano oebug. mainlv because ol the complexitv ol svnchronization when accessing shareo inlormation. vou never know when the threao vou are running is going to be preempteo. which can leao to strange ano inconsistent bugs creeping up when the threao's interleaving is not as expecteo. On the other hano. cooperative multi-threaoing is a "trick" where vou have more than one stack. ano each "threao" ol execution explicitlv oe-scheoules itsell to give time to another "threao". This can relax the svnchronization requirements but can become complex ano error-prone. since the threao scheouling is lelt at the hanos ol the programmers. Hands-on Node Why? 15/147 So|ut|on 2: Use event ca||backs An event callback is a lunction that gets invokeo when something signincant happens e.g. the result ol a oatabase querv is available. To use event callbacks on the previous example. vou coulo change it like so: l. callback = function{post} { 2. doSomethingWithPost{post}; // this will onlv execute when the db.querv function returns. 3. }; 4. db.querv{`SELECT * FROM posts where id = l`, callback}; 5. doSomethingElse{}; // this will execute independent of the returned status of the db.querv call. Here vou are oenning a lunction to be invokeo when the ob operation is complete. then passing this lunction as an callback argument to the ob querv operation. The ob operation becomes responsible lor executing the callback when it completes. You can use an inline anonvmous lunction to express this in a more compact lashion: l. db.querv{`SELECT * FROM posts where id = l`, 2. function{post} { 3. doSomethingWithPost{post}; // this will onlv execute when the db.querv function returns. 4. } 5. }; 6. doSomethingElse{}; // this will execute independent of the returned status of the db.querv call. While ob.querv is executing. the process is lree to continue running ooSomethingElse. ano even service new client requests. Ior quite some time. the C svstems-programming "hacker" communitv has known that event-oriven programming is the best wav to scale a server to hanole manv concurrent connections. It has been known to be more elncient regaroing memorv: less context to store. ano time: less context-switching. This knowleoge has been innltrating other platlorms ano communities: some ol the most well-known event loop implementations are Rubv's Event Machine. Ferl's AnvEvent ano Fvthon's Twisteo. ano there plentv ol others. Tip: Ior more inlo about event-oriven server implementations. see http:en.wikipeoia.orgwikiReactor_pattern. Implementing an application using one ol these lrameworks requires lramework-specinc knowleoge ano lramework-specinc libraries. Ior example: when using Event Machine. vou shoulo avoio using svnchronous libraries i.e. most libraries. To gain the benent ol not blocking. vou are limiteo to using onlv asvnchronous libraries. built specincallv lor Event Machine. Your server will not be able to scale Hands-on Node Why? 16/147 optimallv il the event loop is constantlv blocking which prevents timelv processing ol IO events. Il vou choose to go oown the non-blocking rabbit hole. vou have to go all the wav oown. never compromising. ano hope vou come out on the other sioe in one piece. Nooe has been oeviseo as a non-blocking IO server platlorm lrom oav one. so generallv vou shoulo expect evervthing built on top ol it is non-blocking. Since ]avascript itsell is verv minimal ano ooes not impose anv wav ol ooing IO it ooes not have a stanoaro IO librarv. Nooe has a clean slate to builo upon. Why Javascr|pt? Rvan Dahl began this project builoing a C platlorm. but maintaining the context between callbacks was too complicateo ano coulo to poorlv structureo cooe. so he then turneo to Lua. Lua alreaov has several blocking IO libraries ano this mix ol blocking ano non-blocking coulo conluse average oevelopers ano prevent manv ol them lrom builoing scalable applications. so Lua wasn't ioeal either. Dahl then thought to ]avascript. ]avascript has closures ano nrst-class lunctions. making it inoeeo a powerlul match with eventeo IO programming. Closures are lunctions that inherit the variables lrom their enclosing environment. When a lunction callback executes it will magicallv remember the context in which it was oeclareo. along with all the variables available in that context ano anv "parent" contexts. This powerlul leature is at the heart ol Nooe's success among programming communities. In the web browser. il vou want to listen lor an event. a button click lor instance. vou mav oo something like: l. var clickCount = 0; 2. document.getElementBvId{`mvbutton`}.onclick = function{} { 3. 4. clickCount ++; 5. 6. alert{`Clicked ` + clickCount + ` times.`}; 7. 8. }; 9. or. using jQuerv: l. var clickCount = 0; 2. ${`button#mvbutton`}.click{function{} { 3. clickedCount ++; 4. alert{`Clicked ` + clickCount + ` times.`}; 5. }}; In both examples we assign or pass a lunction as an argument. which mav be executeo later. The click hanoling lunction has access everv variable in scope at the point where the lunction is oeclareo. i.e. practicallv speaking. the click hanoler has access to the clickCount variable. oeclareo in the parent closure. Hands-on Node Why? 17/147 Here we are using a global variable. "clickCount". where we store the number ol times the user has clickeo a button. We can also avoio having a global variable accessible to the rest ol the svstem. bv wrapping it insioe another closure. making the clicked variable onlv accessible within the closure we createo: l. {function{} { 2. var clickCount = 0; 3. ${`button#mvbutton`}.click{function{} { 4. clickCount ++; 5. alert{`Clicked ` + clickCount + ` times.`}; 6. }}; 7. }}{}; In line 7 we are invoking a lunction immeoiatelv alter oenning it. Il this is strange to vou. oon't worrv We will cover this pattern later. How I Learned to Stop Fear|ng and Love Javascr|pt ]avascript has gooo ano bao parts. It was createo in 1995 bv Netscape's Brenoan Eich. in a rush to ship the latest version ol the Netscape web browser. Due to this rush some gooo. even wonoerlul. parts got into ]avascript. but also some bao parts. This book will not cover the oistinction between ]avascript gooo ano bao parts. Ior all we know. we will onlv provioe examples using the gooo parts. Ior more on this topic vou shoulo reao Douglas Crockloro book nameo "]avascript. The Gooo Farts". eoiteo bv O'Reillv. In spite ol its orawbacks. ]avascript quicklv - ano somewhat unpreoictablv - became the oe-lacto language lor web browsers. Back then. ]avascript was useo to primarilv to inspect ano manipulate HTML oocuments. allowing the creation the nrst ovnamic. client-sioe web applications. In late 1998. the Worlo Wioe Web Consortium W3C. stanoaroizeo the Document Object Mooel DOM. an AFI oeviseo to inspect ano manipulate HTML oocuments on the client sioe. In response to ]avascript's quirks ano the initial hatreo towaros the DOM AFI. ]avascript quicklv gaineo a bao reputation. also oue to some incompatibilities between browser venoors ano sometimes even between prooucts lrom the same venoor. Despite milo to lull-blown hate in some oeveloper communities. ]avascript became wioelv aoopteo. Ior better ol lor worse. tooav ]avascript is the most wioelv oeploveo programming language on Earth. Il vou learn the gooo leatures ol the language - such as prototvpical inheritance. lunction closures. etc. - ano learn to avoio or circumvent the bao parts. ]avascript can be a verv pleasant language to work in. Hands-on Node Why? 18/147 Funct|on Dec|arat|on Sty|es A lunction can be oeclareo in manv wavs in ]avascript. The simplest is oeclaring it anonvmouslv: l. function{} { 2. console.log{`hello`}; 3. } Here we oeclare a lunction. but it's not ol much use. because oo not invoke it. What's more. we have no wav to invoke it as it has no name. We can invoke an anonvmous lunction in-place: l. {function{} { 2. console.log{`hello`}; 3. }}{}; Here we are executing the lunction immeoiatelv alter oeclaring it. Notice we wrap the entire lunction oeclaration in parenthesis. We can also name lunctions like this: l. function mvFunction {} { 2. console.log{`hello`}; 3. } Here we are oeclaring a nameo lunction with the name: "mvIunction". mvIunction will be available insioe the scope it's oeclareo mvFunction{}; ano also within inner scopes: l. function mvFunction {} { 2. console.log{`hello`}; 3. } 4. 5. {function{} { 6. mvFunction{}; 7. }}{}; A result ol ]avascript treating lunctions as nrst-class objects means we can assign a lunction to a variable: l. var mvFunc = function{} { 2. console.log{`hello`}; 3. } 4. This lunction is now available as the value ol the mvFunc variable. We can assign that lunction to another variable: Hands-on Node Why? 19/147 var mvFunc2 = mvFunc; Ano invoke them just like anv other lunction: l. mvFunc{}; 2. mvFunc2{}; We can mix both techniques. having a nameo lunction storeo in a variable: l. var mvFunc2 = function mvFunc{} { 2. console.log{`hello`}; 3. } 4. mvFunc2{}; Note though. we cannot access mvIunc lrom outsioe the scope ol mvIunc itsell We can then use a variable or a lunction name to pass variables into lunctions like this: l. var mvFunc = function{} { 2. console.log{`hello`}; 3. } 4. 5. console.log{mvFunc}; or simplv oeclare it inline il we oon't neeo it lor anvthing else: l. console.log{function{} { 2. console.log{`hello`}; 3. }}; Funct|ons are rst-c|ass objects In lact. there are no secono-class objects in ]avascript. ]avascript is the ultimate object-orienteo language. where evervthing is inoeeo. an object. As that. a lunction is an object where vou can set properties. pass it arouno insioe arguments ano return them. Alwavs a pleasure. Example: Hands-on Node Why? 20/147 l. var schedule = function{timeout, callbackfunction} { 2. return { 3. start: function{} { 4. setTimeout{callbackfunction, timeout} 5. } 6. }; 7. }; 8. 9. {function{} { l0. var timeout = l000; // l second ll. var count = 0; l2. schedule{timeout, function doStuff{} { l3. console.log{++ count}; l4. schedule{timeout, doStuff}; l5. }}.start{timeout}; l6. }}{}; l7. l8. // "timeout" and "count" variables l9. // do not exist on this scope. In this little example we create a lunction ano store it in a lunction calleo "scheoule" starting on line 1. This lunction just returns an object that has one propertv calleo "start" line 3. This value ol the "start" propertv is a lunction that. when calleo. sets a timeout line ! to call a lunction that is passeo in as the "timeout" argument. This timeout will scheoule callback lunction to be calleo within the number ol seconos oenneo in the timeout variable passes. On line 9 we oeclare a lunction that will immeoiatelv be executeo on line 1o. This is a normal wav to create new scopes in ]avascript. Insioe this scope we create 2 variables: "timeout" line 10 ano "count" line 11. Note that these variables will not be accessible to the outer scope. Then. on line 12. we invoke the schedule lunction. passing in the timeout value as nrst argument ano a lunction calleo doStuff as secono argument. When the timeout occurs. this lunction will increment the variable count ano log it. ano also call the scheoule all over again. So in this small example we have: lunctions passeo as argument. lunctions to create scope. lunctions to serve as asvnchronous callbacks ano returning lunctions. We also here present the notions ol encapsulation bv hioing local variables lorm the outsioe scope ano recursion the lunction is calling itsell at the eno. In ]avascript vou can even set ano access attributes in a lunction. something like this: l. var mvFunction = function{} { 2. // do something crazv 3. }; 4. mvFunction.somePropertv = `abc`; 5. console.log{mvFunction.somePropertv}; 6. // #=> "abc" ]avascript is inoeeo a powerlul language. ano il vou oon't alreaov oo. vou shoulo learn it ano embrace Hands-on Node Why? 21/147 it's gooo parts. JSL|nt It's not to be covereo here. but ]avascript inoeeo has some bao parts. ano thev shoulo be avoioeo at all costs. One tool that's proven invaluable to the author is ]SLint. bv Douglas Crockloro. ]SLint analvzes vour ]avascript nle ano outputs a series ol errors ano warnings. incluoing some known misuses ol ]avascript. like using globallv-scopeo variables like when vou lorget the "var" kevworo. ano lreezing values insioe iteration that have callbacks that use them. ano manv others that are uselul. ]SLint can be installeo using $ npm install jslint Il vou oon't have NFM installeo see section about NFM. ano can be run lrom the commano line like this: $ jslint mvfile.js To the author ol this book. ]Slint has proven itsell to be an invaluable tool to guarantee he ooesn't lall into some common ]avascript traps. Javascr|pt vers|ons ]avascript is a stanoaro with it's own name - ECMAScript - ano it has gone through various iterations. Currentlv Nooe nativelv supports evervthing the V8 ]avascript engine supports ECMA 3ro eoition ano parts ol the new ECMA 5th eoition. These parts ol ECMA 5 are nicelv oocumenteo on the lollowing github wiki page: https:github.comjoventnooewikiECMA-5-Mozilla-Ieatures-Implementeo-in-V8 Hand||ng ca||backs In Nooe vou can implement vour own lunctions that perlorm asvnchronous IO. To oo so. vou can accept a callback lunction. You will invoke this lunction when the IO is oone. Hands-on Node Why? 22/147 l. var mvAsvncFunction = function{someArgumentl, someArgument2, callback} { 2. // simulate some I/O was done 3. setTimeout{function{} { 4. // l second later, we are done with the I/O, call the callback 5. callback{}; 6. }, l000} 7. } On line 3 we are invoking a setTimeout to simulate the oelav ano asvnchronism ol an IO call. This setTimeout lunction will call the nrst argument - a lunction we oeclare inline - alter 1000 milliseconos the secono argument have gone bv. This inline lunction will then call the callback that was passeo as the thiro argument to mvAsvncFunction. notilving the caller the operation has enoeo. Using this convention ano others like the Event Emitter pattern which we will cover later vou can embrace ]avascript as the ultimate language lor event-oriven applications. Tip: To lollow the Nooe convention. this lunction shoulo receive the error or null il there was no error as nrst argument. ano then some "real" arguments il vou wish to oo so. l. fs.open{`/path/to/file`, function{err, fd} { 2. if {err} { /* handle error */; return; } 3. console.log{`opened file and got file descriptor ` + fd}; 4. }} Here we are using a Nooe AFI lunction fs.open that receives 2 arguments: the path to the nle ano a lunction. which will be invokeo with an error or null on the nrst argument ano a nle oescriptor on the secono. References Event Machine: http:rubveventmachine.com Twisteo: http:twisteomatrix.comtrac AnvEvent: http:soltware.schmorp.oepkgAnvEvent.html ]avascript. the Gooo Farts - Douglas Crockloro - O'Reillv - http:www.amazon.comexecobioosASIN059o5177!2wrrrlowioeweb ]SLint http:www.jslint.com Hands-on Node Why? 23/147 Hands-on Node Why? 24/147 Start|ng up Insta|| Node The tvpical wav ol installing Nooe on vour oevelopment machine is bv lollowing the steps on the nooejs.org website. Nooe shoulo install out ol the box on Linux. Macintosh. ano Solaris. With some ellort vou shoulo be able to get it running on other Unix platlorms ano Winoows either via Cvgwin or MinGW. Nooe has several oepenoencies. but lortunatelv most ol them are oistributeo along with it. Il vou are builoing lrom source vou shoulo onlv neeo 2 things: pvthon - version 2.! or higher. The builo tools oistributeo with Nooe run on pvthon. libssl-oev - Il vou plan to use SSLTLS encrvption in vour networking. vou'll neeo this. Libssl is the librarv useo in the openssl tool. On Linux ano Unix svstems it can usuallv be installeo with vour lavorite package manager. The lib comes pre- installeo on OS X. Fick the latest stable version ano oownloao it: $ wget http://nodejs.org/dist/node~v0.4.7.tar.gz Expano it: $ tar xvfz node~v0.4.7.tar.gz Builo it: l. $ cd node~v0.4.7 2. $ ./configure 3. $ make 4. $ make install Tip: il vou are having permission problems on this last step vou shoulo run the install step as a super user like bv: $ sudo make install Alter vou are oone. vou shoulo be able to run the nooe executable on the commano line: l. $ node ~v 2. v0.4.7 Hands-on Node Starting up 25/147 The node executable can be executeo in two main lashions: CLI commano-line interlace or nle. To launch the CLI. just tvpe $ node ano vou will get a ]avascript commano line prompt. which vou can use to evaluate ]avascript. It's great lor kicking the tires ano trving out some stull quicklv. You can also launch Nooe on a nle. which will make Nooe parse ano evaluate the ]avascript on that nle. ano when it enos ooing that. it enters the event loop. Once insioe the event loop. nooe will exit il it has nothing to oo. or will wait ano listen lor events. You can launch Nooe on a nle like this: $ node mvfile.js or. il vou wish. vou can also make vour nle oirectlv executable bv changing the permissions like this: $ chmod o+x mvfile.js ano insert the lollowing as the nrst line ol the nle: #!/usr/bin/env node You can then execute the nle oirecltv: $ ./mvfile.js NPM - Node Package Manager NFM has become the stanoaro lor managing Nooe packages throughout time. ano tight collaboration between Isaac Schlueter - the original author ol NFM - ano Rvan Dahl - the author ano maintainer on Nooe - has lurther tighteneo this relationship to the point where. starting at version 0.!.0. Nooe supports the package.json nle lormat lormat to inoicate oepenoencies ano package starting nle. To install it vou tvpe: $ curl http://npmjs.org/install.sh sh Il that lails. trv this on a temporarv oirectorv: l. $ git clone http://github.com/isaacs/npm.git 2. $ cd npm 3. $ sudo make install NPM commands Hands-on Node Starting up 26/147 NFM can be useo on the commano line. The basic commanos are: npm |s [|ter] Use this to see the list ol all packages ano their versions npm ls with no nlter. or nlter bv a tag npm nlter tag. Examples: List all installeo packages: $ npm ls installed List all stable packages: $ npm ls stable You can also combine nlters: $ npm ls installed stable You can also use npm ls to search bv name: $ npm ls fug this will return all packages that have "lug" insioe its name or tags You can also querv it bv version. prenxeo with the "(" character: $ npm ls @l.0 npm |nsta|| package[@|ters] With this commano vou can install a package ano all the packages it oepenos on. To install the latest version ol a package oo: $ npm install package_name Example: $ npm install express To install a specinc version ol a package oo: $npm install package_name@version Example: $ npm install express@2.0.0beta To install the latest within a version range vou can specilv. lor instance: $ npm install express@">=0.l.0 <0.2.0" You can also combine manv nlters to select a specinc version. combining version range ano or tags like this: Hands-on Node Starting up 27/147 $ npm install sax@">=0.l.0 <0.2.0" bench supervisor npm rm package_name[@vers|on] [package_name[@vers|on] ...] Use this commano to uninstall packages. Il versions are omitteo. then all the louno versions are removeo. Example: $ npm rm sax npm v|ew To view all ol a package inlo. Delaults to the latest version il version is omitteo. View the latest inlo on the "connect" package: $ npm view connect View inlormation about a specinc version: $ npm view connect@l.0.3 Iurther on we will look more into NFM ano how it can help us bunole ano "lreeze" application oepenoencies. Hands-on Node Starting up 28/147 Understand|ng Understand|ng the Node event |oop Nooe makes eventeo IO programming simple ano accessible. putting speeo ano scalabilitv on the nngertips ol the common programmer. But the event loop comes with a price. Even though vou are not aware ol it ano Nooe makes a gooo job at this. vou shoulo unoerstano how it works. Everv gooo programmer shoulo know the intricacies ol the platlorms he she is builoing lor. its oo's ano oon'ts. ano in Nooe it shoulo be no oillerent. An event-queue process|ng |oop You shoulo think ol the event loop as a loop that processes an event queue. Interesting events happen. ano when thev oo. thev go in a queue. waiting lor their turn. Then. there is an event loop popping out these events. one bv one. ano invoking the associateo callback lunctions. one at a time. The event loop pops one event out ol the queue ano invokes the associateo callback. When the callback returns the event loop pops the next event ano invokes the associateo callback lunction. When the event queue is emptv. the event loop waits lor new events il there are some penoing calls or servers listening. or just quits ol there are none. So. let's jump into our nrst Nooe example. Write a nle nameo hello.js with the lollowing content: Source code in chapters/understanding/l_hello.js l. setTimeout{function{} { 2. console.log{`World!`}; 3. }, 2000}; 4. console.log{`Hello`}; Run it using the nooe commano line tool: $ node hello.js You shoulo see the woro "Hello" written out. ano then. 2 seconos later. "Worlo". Shoulon't "Worlo" have been written nrst since it appears nrst on the cooe? No. ano to answer that properlv we must analvze what happens when executing this small program. On line 1 we oeclare an anonvmous lunction that prints out "Worlo". This lunction. which is not vet executeo. is passeo in as the nrst argument to a setTimeout call. which scheoules this lunction to run in 2000 milliseconos. Then. on line !. we output "Hello" into the console. Two seconos later the anonvmous lunction we passeo in as an argument to the setTimeout call is invokeo. printing "Worlo". Hands-on Node Understanding 29/147 So. the nrst argument to the setTimeout call is a lunction we call a "callback". It's a lunction which will be calleo later. when the event we set out to listen to in this case. a time-out ol 2 seconos occurs. We can also pass callback lunctions to be calleo on events like when a new TCF connection is establisheo. some nle oata is reao or some other tvpe ol IO event. Alter our callback is invokeo. printing "Worlo". Nooe unoerstanos that there is nothing more to oo ano exits. Ca||backs that w||| generate events Let's complicate this a bit lurther. Let's keep Nooe busv ano keep on scheouling callbacks like this: Source code in chapters/understanding/2_repeat.js l. {function schedule{} { 2. setTimeout{function{} { 3. console.log{`Hello World!`}; 4. schedule{}; 5. }, l000}; 6. }}{}; Here we are wrapping the whole thing insioe a lunction nameo "scheoule". ano we are invoking it immeoiatelv alter oeclaring it on line o. This lunction will scheoule a callback to execute in 1 secono. This callback. when invokeo. will print "Hello Worlo" ano then run schedule again. On everv callback we are registering a new one to be invokeo one secono later. never letting Nooe nnish. This little script will just keep printing "Hello Worlo". Don't b|ockI Nooe primarv concern ano the main use case lor an event loop is to create highlv scalable servers. Since an event loop runs in a single threao. it onlv processes the next event when the callback nnishes. Il vou coulo see the call stack ol a busv Nooe application vou woulo see it going up ano oown reallv last. invoking callbacks ano picking up the next event in line. But lor this to work well vou have to clear the event loop as last as vou can. There are two main categories ol things that can block the event loop: svnchronous IO ano big loops. Nooe AFI is not all asvnchronous. Some parts ol it are svnchronous like. lor instance. some nle operations. Don't worrv. thev are verv well markeo: thev alwavs terminate in "Svnc" - like ls.reaoIileSvnc - . ano thev shoulo not be useo. or useo onlv when initializing. On a working server vou shoulo never use a blocking IO lunction insioe a callback. since vou're blocking the event loop ano preventing other callbacks - probablv belonging to other client connections - lrom being serveo. Hands-on Node Understanding 30/147 One lunction that is svnchronous ano ooes not eno in "Svnc" is the "require" lunction. which shoulo onlv be useo when initializing an app or a mooule. Tip: Don't put a require statement insioe a callback. since it is svnchronous ano thus will slow oown vour event loop. The secono categorv ol blocking scenarios is when vou are perlorming loops that take a lot ol time. like iterating over thousanos ol objects or ooing complex time-taking operations in memorv. There are several techniques that can be useo to work arouno that. which we'll cover later. Here is a case where we present some simple cooe that blocks the event loop: l. var open = false; 2. 3. setTimeout{function{} { 4. open = true; 5. }, l000} 6. 7. while{!open} { 8. // wait 9. } l0. ll. console.log{`opened!`}; Here we are setting a timeout. on line 3. that invokes a lunction that will set the open variable to true. This lunction is set to be triggereo in one secono. On line 7 we are waiting lor the variable to become true. We coulo be leao to believe that. in one secono the timeout will happen ano set open to true. ano that the while loop will stop ano that we will get "openeo" line 11 printeo. But this never happens. Nooe will never execute the timeout callback because the event loop is stuck on this while loop starteo on line 7. never giving it a chance to process the timeout event Understand|ng Modu|es Client-sioe ]avascript has a bao reputation also because ol the common namespace shareo bv all scripts. which can leao to connicts ano securitv leaks. Nooe implements the Common]S mooules stanoaro. where each mooule is separateo lrom the other mooules. having a separate namespace to plav with. ano exporting onlv the oesireo properties. To incluoe an existing mooule vou can use the require lunction like this: var module = require{`module_name`}; This will letch a mooule that was installeo bv npm. Il vou want to author mooules as vou shoulo Hands-on Node Understanding 31/147 when ooing an application. vou can also use the relative notation like this: var module = require{"./path/to/module_name"}; This will letch the mooule relativelv to the current nle we are executing. We will cover creating mooules on a later section. In this lormat vou can use an absolute path starting with "" or a relative one starting with ".". Mooules are loaoeo onlv once per process. that is. when vou have several require calls to the same mooule. Nooe caches the require call il it resolves to the same nle. Which leaos us to the next chapter. How Node reso|ves a modu|e path So. how ooes nooe resolve a call to "requiremooule_path"? Here is the recipe: Core modu|es There are a list ol core mooules. which Nooe incluoes in the oistribution binarv. Il vou require one ol those mooules. Nooe just returns that mooule ano the require enos. Modu|es w|th comp|ete or re|at|ve path Il the mooule path begins with "." or "". Nooe tries to loao the mooule as a nle. Il it ooes not succeeo. it tries to loao the mooule as a oirectorv. As a |e When loaoing as a nle. il the nle exists. Nooe just loaos it as ]avascript text. Il not. it tries ooing the same bv appenoing ".js" to the given path. Il not. it tries appenoing ".nooe" ano loao it as a binarv aoo-on. As a d|rectory Il appenoing "package.json" is a nle. trv loaoing the package oennition ano look lor a "main" nelo. Trv to loao it as a nle. Il unsuccesslul. trv to loao it bv appenoing "inoex" to it. As an |nsta||ed modu|e Il the mooule path ooes not begin with "." or "" or il loaoing it with complete or relative paths ooes not work. Nooe tries to loao the mooule as a mooule that was previouslv installeo. Ior that it aoos "nooe_mooules"to the current oirectorv ano tries to loao the mooule lrom there. Il it ooes not Hands-on Node Understanding 32/147 succeeo it tries aooing "nooe_mooules" to the parent oirectorv ano loao the mooule lrom there. Il it ooes not succeeo it moves again to the parent oirectorv ano so on. until either the mooule is louno or the root ol the tree is louno. This means that vou can put vour bunole vour Nooe mooules into vour app oirectorv. ano Nooe will nno those. Later we will see how using this leature together with NFM we can bunole ano "lreeze" vour application oepenoencies. Also vou can. lor instance. have a nooe_mooules oirectorv on the home loloer ol each user. ano so on. Nooe tries to loao mooules lrom these oirectories. starting nrst with the one that is closest up the path. Hands-on Node Understanding 33/147 API qu|ck tour Nooe provioes a platlorm AFI that covers mainlv ! aspects: processes nlesvstem networking utilities This book is not meant to be a comprehensive coverage ol the whole Nooe AFI. Ior that vou shoulo consult the Nooe online oocumentation on http:nooejs.org. Processes Nooe allows vou to analvze vour process environment variables. etc. ano manage external processes. The involveo mooules are: process Inquire the current process to know the FID. environment variables. platlorm. memorv usage. etc. ch||d_process Spawn ano kill new processes. execute commanos ano pipe their outputs. F||e system Nooe also provioes a low-level AFI to manipulate nles. which is inspireo bv the FOSIX stanoaro. ano is compriseo bv the lollowing mooules: fs Iile manipulation: create. remove. loao. write ano reao nles. Create reao ano write streams covereo later. path Hands-on Node AP quick tour 34/147 Normalize ano join nle paths. Check il a nle exists or is a oirectorv. Network|ng net Create a TCF server or client. dgram Receive ano seno UDF packets. http Create an HTTF server or Client. t|s (ss|j The tls mooule uses OpenSSL to provioe Transport Laver Securitv anoor Secure Socket Laver: encrvpteo stream communication. https Implementing http over TLSSSL. dns Asvnchronous DNS resolution. Hands-on Node AP quick tour 35/147 Ut|||t|es conso|e Nooe provioes a global "console" object to which vou can output strings using: console.log{"Hello"}; This simplv outputs the string into the process stdout alter lormatting it. You can pass in. insteao ol a string. an object like this: l. var a = {l: true, 2: false}; 2. console.log{a}; // => { `l`: true, `2`: false } In this case console.log outputs the object using util.inspect covereo later. You can also use string interpolation like this: l. var a = {l: true, 2: false}; 2. console.log{`This is a number: %d, and this is a string: %s, and this is an object outputted as JSON: %j`, 42, `Hello`, a}; 3. Which outputs: This is a number: 42, and this is a string: Hello, and this is an object outputted as JSON: {"l":true,"2":false} console also allows vou to write into the the stoerr using: console.warn{"Warning!"}; ano to print a stack trace: console.trace{}; Hands-on Node Utilities 36/147 l. Trace: 2. at |object Context1:l:9 3. at Interface.<anonvmous> {repl.js:l7l:22} 4. at Interface.emit {events.js:64:l7} 5. at Interface._onLine {readline.js:l53:l0} 6. at Interface._line {readline.js:408:8} 7. at Interface._ttvWrite {readline.js:585:l4} 8. at ReadStream.<anonvmous> {readline.js:73:l2} 9. at ReadStream.emit {events.js:8l:20} l0. at ReadStream._emitKev {ttv_posix.js:307:l0} ll. at ReadStream.onData {ttv_posix.js:70:l2} l2. ut|| Nooe has an util mooule which which bunoles some lunctions like: l. var util = require{`util`}; 2. util.log{`Hello`}; which outputs a the current timestamp ano the given string like this: l4 Mar l6:38:3l ~ Hello The inspect lunction is a nice utilitv which can aio in quick oebugging bv inspecting ano printing an object properties like this: l. var util = require{`util`}; 2. var a = {l: true, 2: false}; 3. console.log{util.inspect{a}}; 4. // => { `l`: true, `2`: false } util.inspect accepts more arguments. which are: util.inspect{object, showHidden, depth = 2, showColors}; the secono argument. showHidden shoulo be turneo on il vou wich inspect to show vou non- enumerable properties. which are properties that belong to the object prototvpe chain. not the object itsell. depth. the thiro argument. is the oelault oepth on the object graph it shoulo show. This is uselul lor inspecting large objects. To recurse inoennitelv. pass a null value. Tip: util.inspect keeps track ol the visiteo objects. so circular oepenoencies are no problem. ano will appear as "|Circular|" on the outputteo string. The util mooule has some other niceties. such as inheritance setup ano stream pumping. but thev belong on more appropriate chapters. Hands-on Node Utilities 37/147 Hands-on Node Utilities 38/147 Buffers Nativelv. ]avascript is not verv gooo at hanoling binarv oata. So Nooe aoos a native buller implementation with a ]avascript wav ol manipulating it. It's the stanoaro wav in Nooe to transport oata. Generallv. vou can pass bullers on everv Nooe AFI requiring oata to be sent. Also. when receiving oata on a callback. vou get a buller except when vou specilv a stream encooing. in which case vou get a String. This wil be covereo later. You can create a Buller lrom an UTI8 string like this: var buf = new Buffer{`Hello World!`}; You can also create a buller lrom strings with other encooings. as long as vou pass it as the secono argument: var buf = new Buffer{`8b76fde7l3ce`, `base64`}; Accepteo encooings are: "ascii". "utl8" ano "baseo!". or vou can create a new emptv buller with a specinc size: var buf = new Buffer{l024}; ano vou can manipulate it: buf|201 = 56; // set bvte 20 to 56 You can also convert it to a UTI-8-encooeo string: var str = buf.toString{}; or into a string with an alternative encooing: var str = buf.toString{`base64`}; UTI-8 is the oelault encooing lor Nooe. so. in a general wav. il vou omit it as we oio on the buffer.toString{} call. UTI-8 will be assumeo. S||ce a buffer A buller can be sliceo into a smaller buller bv using the appropriatelv nameo slice{} methoo like this: Hands-on Node Buffers 39/147 l. var buffer = new Buffer{`this is the string in mv buffer`}; 2. var slice = buffer.slice{l0, 20}; Here we are slicing the original buller that has 31 bvtes into a new buller that has 10 bvtes equal to the 10th to 20th bvtes on the original buller. Note that the slice lunction ooes not create new buller memorv: it uses the original untoucheo buller unoerneath. Tip: Il vou are alraio vou will be wasting precious memorv bv keeping the olo buller arouno when slicing it. vou can copv it into another like this: Copy a buffer You can copv a part ol a buller into another pre-allocateo buller like this: l. var buffer = new Buffer{`this is the string in mv buffer`}; 2. var slice = new Buffer{l0}; 3. var targetStart = 0, 4. sourceStart = l0, 5. sourceEnd = 20; 6. buffer.copv{slice, targetStart, sourceStart, sourceEnd}; Here we are copving part ol buffer into slice. but onlv positions 10 through 20. Buffer Exerc|ses Exerc|se 1 Create an uninitializeo buller with 100 bvtes length ano nll it with bvtes with values starting lrom 0 to 99. Ano then print its contents. Exerc|se 2 Do what is askeo on the previous exercise ano then slice the buller with bvtes ranging !0 to o0. Ano then print it. Exerc|se 3 Do what is askeo on exercise 1 ano then copv bvtes ranging !0 to o0 into a new buller. Ano then print it. Hands-on Node Buffers 40/147 Hands-on Node Buffers 41/147 Event Em|tter On Nooe manv objects can emit events. Ior instance. a TCF server can emit a 'connect' event everv time a client connects. Or a nle stream request can emit a 'oata' event. .addL|stener You can listen lor these events bv calling one ol these objects "aooListener" methoo. passing in a callback lunction. Ior instance. a nle ReaoStream can emit a "oata" event everv time there is some oata available to reao. Insteao ol using the "aooListener" lunction. vou can also use "on". which is exactlv the same thing: l. var fs = require{`fs`}; // get the fs module 2. var readStream = fs.createReadStream{`/etc/passwd`}; 3. readStream.on{`data`, function{data} { 4. console.log{data}; 5. }}; 6. readStream.on{`end`, function{} { 7. console.log{`file ended`}; 8. }}; Here we are binoing to the readStream's "oata" ano "eno" events. passing in callback lunctions to hanole each ol these cases. When one ol these events happens. the reaoStream will call the callback lunction we pass in. You can either pass in an anonvmous lunction as we are ooing here. or vou can pass a lunction name lor a lunction available on the current scope. or even a variable containing a lunction. .once You mav also want to listen lor an event exactlv once. Ior instance. il vou want to listen to the nrst connection on a server. vou shoulo oo something like this: l. server.once{`connection`, function {stream} { 2. console.log{`Ah, we have our first user!`}; 3. }}; This works exactlv like our "on" example. except that our callback lunction will be calleo at most once. It has the same ellect as the lollowing cooe: Hands-on Node Event Emitter 42/147 l. function connListener{stream} { 2. console.log{`Ah, we have our first user!`}; 3. server.removeListener{`connection`, connListener}; 4. } 5. server.on{`connection`, connListener}; Here we are using the removeListener. which also belongs to the EventEmitter pattern. It accepts the event name ano the lunction it shoulo remove. .removeA||L|steners Il vou ever neeo to. vou can also remove all listeners lor an event lrom an Event Emitter bv simplv calling server.removeAllListeners{`connection`}; Creat|ng an Event Em|tter Il vou are interesteo on using this Event Emitter pattern - ano vou shoulo - throughout vour application. vou can. You can create a pseuoo-class ano make it inherit lrom the EventEmitter like this: l. var EventEmitter = require{`events`}.EventEmitter, 2. util = require{`util`}; 3. 4. // Here is the MvClass constructor: 5. var MvClass = function{optionl, option2} { 6. this.optionl = optionl; 7. this.option2 = option2; 8. } 9. l0. util.inherits{MvClass, EventEmitter}; util.inherits is setting up the prototvpe chain so that vou get the EventEmitter prototvpe methoos available to vour MvClass instances. This wav instances ol MvClass can emit events: l. MvClass.prototvpe.someMethod = function{} { 2. this.emit{`custom event`, `some arguments`}; 3. } 4. Here we are emiting an event nameo "custom event". senoing also some oata "some arguments" in this case. Hands-on Node Event Emitter 43/147 Now clients ol MvClass instances can listen to "custom events" events like this: l. var mvInstance = new MvClass{l, 2}; 2. mvInstance.on{`custom event`, function{} { 3. console.log{`got a custom event!`}; 4. }}; Tip: The Event Emitter is a nice wav ol enlorcing the oecoupling ol interlaces. a soltware oesign technique that improves the inoepenoence lrom specinc interlaces. making vour cooe more nexible. Event Em|tter Exerc|ses Exerc|se 1 Builo a pseuoo-class nameo "Ticker" that emits a "tick" event everv 1 secono. Exerc|se 2 Builo a script that instantiates one Ticker ano bino to the "tick" event. printing "TICK" everv time it gets one. Hands-on Node Event Emitter 44/147 T|mers Nooe implements the timers AFI also louno in web browsers. The original AFI is a bit quirkv. but it hasn't been changeo lor the sake ol consistencv. setT|meout setTimeout lets vou scheoule an arbitrarv lunction to be executeo in the luture. An example: l. var timeout = 2000; // 2 seconds 2. setTimeout{function{} { 3. console.log{`timed out!`}; 4. }, timeout}; 5. This cooe will register a lunction to be calleo when the timeout expires. Again. as in anv place in ]avascript. vou can pass in an inline lunction. the name ol a lunction or a variable which value is a lunction. You can use setTimeout with a timeout value ol 0 so that the lunction vou pass gets executeo some time alter the stack clears. but with no waiting. This can be useo to. lor instance scheoule a lunction that ooes not neeo to be executeo immeoiatelv. This was a trick sometimes useo on browser ]avascript. but. as we will see. Nooe process.nextTick{} can be useo insteao ol this. ano it's more elncient. c|earT|meout setTimeout returns a timeout hanole that vou can use to oisable it like this: l. var timeoutHandle = setTimeout{function{} { console.log{`vehaa!`}; }, l000}; 2. clearTimeout{timeoutHandle}; Here the timeout will never execute because we clear it right alter we set it. Another example: Source code in chapters/timers/timers_l.js Hands-on Node Timers 45/147 l. var timeoutA = setTimeout{function{} { 2. console.log{`timeout A`}; 3. }, 2000}; 4. 5. var timeoutB = setTimeout{function{} { 6. console.log{`timeout B`}; 7. clearTimeout{timeoutA}; 8. }, l000}; 9. Here we are starting two timers: one with 1 secono timeoutB ano the other with 2 seconos timeoutA. But timeoutB which nres nrst unscheoules timeoutA on line 7. so timeoutA is never executes - ano the program exits right alter line 7 is executeo. setInterva| Set interval is similar to set timeout. but scheoules a given lunction to run everv X seconos like this: Source code in chapters/timers/timers_2.js l. var period = l000; // l second 2. var interval = setInterval{function{} { 3. console.log{`tick`}; 4. }, period}; This will inoennitelv keep the console logging "tick" unless vou terminate Nooe. You can unscheoule an interval bv calling: c|earInterva| clearInterval unscheoules a running interval previous scheouleo with setInterval. l. var interval = setInterval{...}; 2. clearInterval{interval}; 3. Here we are using the setInterval return value storeo on the interval variable to unscheoule it on line 2. process.nextT|ck You can also scheoule a callback lunction to run on the next run ol the event loop. You can use it like this: Hands-on Node Timers 46/147 l. process.nextTick{function{} { 2. // this runs on the next event loop 3. console.log{`vav!`}; 4. }}; As we saw. this methoo is prelereo to setTimeout{fn, 0} because it is more elncient. Escap|ng the event |oop On each loop. the event loop executes the queueo IO events sequentiallv bv calling the associateo callbacks. Il. on anv ol the callbacks vou take too long. the event loop won't be processing other penoing IO events meanwhile. This can leao to waiting customers or tasks. When executing something that mav take too long. vou can oelav the execution until the next event loop. so waiting events will be processeo meanwhile. It's like going to the back ol the line on a waiting line. To escape the current event loop vou can use process.nextTick like this: l. process.nextTick{function{} { 2. // do something 3. }}; You can use this to oelav processing that is not necessarv to oo immeoiatelv to the next event loop. Ior instance. vou mav neeo to remove a nle. but perhaps vou oon't neeo to oo it belore replving to the client. So. vou coulo oo something like this: l. stream.on{`data`, function{data} { 2. stream.end{`mv response`}; 3. process.nextTick{function{} { 4. fs.unlink{`path/to/file`}; 5. }} 6. }}; Hands-on Node Timers 47/147 A note on ta|| recurs|on Let's sav vou want to scheoule a lunction that ooes some IO - like parsing a log nle - to execute periooicallv. ano vou want to guarantee that no two ol those lunctions are executing at the same time. The best wav is not to use a setInterval. since vou oon't have that guarantee. The interval will nre no matter il the lunction has nnisheo it's outv or not. Supposing there is an asvnchronous lunction calleo "asvnc" that perlorms some IO ano that gets a callback to be invokeo when nnisheo. ano vou want to call it everv secono: l. var interval = l000; // l second 2. setInterval{function{} { 3. asvnc{function{} { 4. console.log{`asvnc is done!`}; 5. }}; 6. }, interval}; Il anv two asvnc calls can't overlap. vou are better oll using tail recursion like this: l. var interval = l000; // l second 2. {function schedule{} { 3. setTimeout{function{} { 4. asvnc{function{} { 5. console.log{`asvnc is done!`}; 6. schedule{}; 7. }}; 8. }, interval} 9. }}{}; Here we are oeclaring a lunction nameo scheoule line 2 ano we are invoking it immeoiatelv alter we are oeclaring it line 9. This lunction scheoules another lunction to execute within one secono line 3 to 8. This other lunction will then call asvnc line !. ano onlv when asvnc is oone we scheoule a new one bv calling scheoule again line o. this time insioe the scheoule lunction. This wav we can be sure that no two calls to asvnc execute simultaneouslv in this context. The oillerence is that we probablv won't have asvnc calleo everv secono unless asvnc takes no time to execute. but we will have it calleo 1 secono alter the last one nnisheo. Hands-on Node Timers 48/147 Low-|eve| |e-system Nooe has a nice streaming AFI lor oealing with nles in an abstract wav. as il thev were network streams. but sometimes vou might neeo to go oown a level ano oeal with the nlesvstem itsell. Iirst. a nice set ol utilities: fs.stat and fs.fstat You can querv some meta-inlo on a nle or oir bv using fs.stat like this: l. var fs = require{`fs`}; 2. 3. fs.stat{`/etc/passwd`, function{err, stats} { 4. if {err} {console.log{err.message}; return; } 5. console.log{stats}; 6. //console.log{`this file is ` + stats.size + ` bvtes long.`}; 7. }}; Il vou print the stats object it will be something like: l. { dev: 23488l026, 2. ino: 24606, 3. mode: 33l88, 4. nlink: l, 5. uid: 0, 6. gid: 0, 7. rdev: 0, 8. size: 3667, 9. blksize: 4096, l0. blocks: 0, ll. atime: Thu, l7 Mar 20ll 09:l4:l2 GMT, l2. mtime: Tue, 23 Jun 2009 06:l9:47 GMT, l3. ctime: Fri, l4 Aug 2009 20:48:l5 GMT l4. } stats is a Stats instance. with which vou can call: Hands-on Node Low-level file-system 49/147 l. stats.isFile{} 2. stats.isDirectorv{} 3. stats.isBlockDevice{} 4. stats.isCharacterDevice{} 5. stats.isSvmbolicLink{} 6. stats.isFIFO{} 7. stats.isSocket{} Il vou have a plain nle oescriptor vou can use fs.fstat{fileDescriptor, callback} insteao. More about nle oescriptors later. Il vou are using the low-level nlesvstem AFI in Nooe. vou will get nle oescriptors as a wav to represent nles. These nle oescriptors are plain integer numbers that represent a nle in vour Nooe process. much like in C FOSIX AFIs. Open a |e You can open a nle bv using ls.open like this: l. var fs = require{`fs`}; 2. fs.open{`/path/to/file`, `r`, function{err, fd} { 3. // got fd 4. }}; The nrst argument to fs.open is the nle path. The secono argument is the nags. which inoicate the mooe with which the nle is to be open. The nags can be 'r'. 'r-'. 'w'. 'w-'. 'a'. or 'a-'. Here is the semantics ol each nag. taken lrom the lopen man page: r - Open text nle lor reaoing. The stream is positioneo at the beginning ol the nle. r+ - Open lor reaoing ano writing. The stream is positioneo at the beginning ol the nle. w - Truncate nle to zero length or create text nle lor writing. The stream is positioneo at the beginning ol the nle. w+ - Open lor reaoing ano writing. The nle is createo il it ooes not exist. otherwise it is truncateo. The stream is positioneo at the beginning ol the nle. a - Open lor writing. The nle is createo il it ooes not exist. The stream is positioneo at the eno ol the nle. Subsequent writes to the nle will alwavs eno up at the then current eno ol nle. a+ - Open lor reaoing ano writing. The nle is createo il it ooes not exist. The stream is positioneo at the eno ol the nle. Subsequent writes to the nle will alwavs eno up at the then current eno ol nle. On the callback lunction. vou get a secono argument lo. which is a nle oescriptor- nothing more than an integer that ioentines the open nle. which vou can use like a hanoler to reao ano write lrom. Hands-on Node Low-level file-system 50/147 Read from a |e Once it's open. vou can also reao lrom a nle like this: Source code in chapters/fs/read.js l. var fs = require{`fs`}; 2. fs.open{`/var/log/svstem.log`, `r`, function{err, fd} { 3. if {err} { throw err } 4. var readBuffer = new Buffer{l024}, 5. bufferOffset = 0, 6. bufferLength = readBuffer.length, 7. filePosition = l00; 8. 9. fs.read{fd, readBuffer,bufferOffset, bufferLength, filePosition, l0. function{err, readBvtes} { ll. if {err} { throw err; } l2. console.log{`just read ` + readBvtes + ` bvtes`}; l3. if {readBvtes > 0} { l4. console.log{readBuffer.slice{0, readBvtes}}; l5. } l6. }}; l7. }}; Here we are opening the nle. ano when it's openeo we are asking to reao a chunk ol 102! bvtes lrom it. starting at position 100 line 9. The last argument to the fs.read call is a callback lunction line 10 which will be invokeo when one ol the lollowing 3 happens: there is an error. something has been reao or nothing coulo be reao. On the nrst argument. this callback gets an error il there was an one. or null. On the secono argument readBvtes it gets the number ol bvtes reao into the buller. Il the reao bvtes is zero. the nle has reacheo the eno. Wr|te |nto a |e To write into a nle oescriptor vou can use fs.write like this: Hands-on Node Low-level file-system 51/147 l. var fs = require{`fs`}; 2. 3. fs.open{`/var/log/svstem.log`, `a`, function{err, fd} { 4. var writeBuffer = new Buffer{`writing this string`}, 5. bufferOffset = 0, 6. bufferLength = writeBuffer.length, 7. filePosition = null; 8. 9. fs.write{ l0. fd, ll. writeBuffer, l2. bufferOffset, l3. bufferLength, l4. filePosition, l5. function{err, written} { l6. if {err} { throw err; } l7. console.log{`wrote ` + written + ` bvtes`}; l8. } l9. }; 20. }}; Here we are opening the nle in appeno-mooe 'a' on line 3. ano then we are writing into it line 8. passing in a buller with the oata we want written. an ollset insioe the buller where we want to start writing lrom. the length ol what we want to write. the nle position ano a callback. In this case we are passing in a nle position ol null. which is to sav that he writes at the current nle position. Here we are also opening in appeno-mooe. so the nle cursor is positioneo at the eno ol the nle. C|ose Your |es On all these examples we oio not close the nles. This is because these are small simple examples oestineo to be run ano returneo. All open nles will be closeo once the process exists. In real applications vou shoulo keep track ol those nle oescriptors ano eventuallv close them using fs.close{fd|, callback1} when no longer neeoeo. Hands-on Node Low-level file-system 52/147 Advanced T|p: carefu| when append|ng concurrent|y Il vou are using these low-level nle-svstem lunctions to appeno into a nle. ano concurrent writes will be happening. opening it in appeno-mooe will not be enough to ensure there will be no overlap. Insteao. vou shoulo keep track ol the last written position belore vou write. ooing something like this: l. // Appender 2. var fs = require{`fs`}; 3. var startAppender = function{fd, startPos} { 4. var pos = startPos; 5. return { 6. append: function{buffer, callback} { 7. var oldPos = pos; 8. pos += buffer.length; 9. fs.write{fd, buffer, 0, buffer.length, oldPos, callback}; l0. } ll. }; l2. }; l3. l4. Here we oeclare a lunction storeo on a variable nameo "startAppenoer". This lunction starts the appenoer state position ano nle oescriptor ano then returns an object with an appeno lunction. Now let's oo a script that uses this Appenoer: l. // start appender 2. fs.open{`/tmp/test.txt`, `w`, function{err, fd} { 3. if {err} {throw err; } 4. var appender = startAppender{fd, 0}; 5. appender.append{new Buffer{`append this!`}, function{err} { 6. console.log{`appended`}; 7. }}; 8. }}; Ano here we are using the appenoer to salelv appeno into a nle. This lunction can then be invokeo to appeno. ano this appenoer will keep track ol the last position line ! on the Appenoer. ano increments it accoroing to the buller length that was passeo in. Hands-on Node Low-level file-system 53/147 Actuallv. there is a problem with this cooe: fs.write{} mav not write all the oata we askeo it to. so we neeo to oo something a little bit smarter here: Source code in chapters/fs/appender.js l. // Appender 2. var fs = require{`fs`}; 3. var startAppender = function{fd, startPos} { 4. var pos = startPos; 5. return { 6. append: function{buffer, callback} { 7. var written = 0; 8. var oldPos = pos; 9. pos += buffer; l0. {function trvWriting{} { ll. if {written < buffer.length} { l2. fs.write{fd, buffer, written, buffer.length ~ written, oldPos + written, l3. function{err, bvtesWritten} { l4. if {err} { callback{err}; return; } l5. written += bvtesWritten; l6. trvWriting{}; l7. } l8. }; l9. } else { 20. // we have finished 2l. callback{null}; 22. } 23. }}{}; 24. } 25. } 26. }; Here we use a lunction nameo "trvWritting" that will trv to write. call ls.write. calculate how manv bvtes have alreaov been written ano call itsell il neeoeo. When it oetects it has nnisheo written ~~ buller.length it calls callback to notilv the caller. enoing the loop. Don't be lrustrateo il vou oon't grasp this on the nrst time arouno. Give it some time to sink in ano come back here alter vou have nnisheo reaoing this book. Also. the appenoing client is opening the nle with mooe "w". which truncates the nle. ano it's telling appenoer to start appenoing on position 0. This will overwrite the nle il it has content. So. a wizer version ol the appenoer client woulo be: Hands-on Node Low-level file-system 54/147 l. // start appender 2. fs.open{`/tmp/test.txt`, `a`, function{err, fd} { 3. if {err} {throw err; } 4. fs.fstat{fd, function{err, stats} { 5. if {err} {throw err; } 6. console.log{stats}; 7. var appender = startAppender{fd, stats.size}; 8. appender.append{new Buffer{`append this!`}, function{err} { 9. console.log{`appended`}; l0. }}; ll. }} l2. }}; F||e-system Exerc|ses You can check out the solutions at the eno ol this book. Exerc|se 1 - get the s|ze of a |e Having a nle nameo a.txt. print the size ol that nles in bvtes. Exerc|se 2 - read a chunk from a |e Having a nle nameo a.txt. print bvtes 10 to 1!. Exerc|se 3 - read two chunks from a |e Having a nle nameo a.txt. print bvtes 5 to 9. ano when oone. reao bvtes 10 to 1!. Exerc|se 4 - Overwr|te a |e Having a nle nameo a.txt. Overwrite it with the UTI8-encooeo string "ABCDEIGHI]LKLMNOFQRSTUVXYZ0123!5o789abcoelghijklmnopqrstuvxvz". Exerc|se 5 - append to a |e Having a nle nameo a.txt. appeno utl8-encooeo string "abc" to nle a.txt. Hands-on Node Low-level file-system 55/147 Exerc|se 6 - change the content of a |e Having a nle nameo a.txt. change bvte at pos 10 to the UTI8 value ol "7". Hands-on Node Low-level file-system 56/147 HTTP HTTP Server You can easilv create an HTTF server in Nooe. Here is the lamous http server "Hello Worlo" example: Source in file: http/http_server_l.js l. var http = require{`http`}; 2. 3. var server = http.createServer{}; 4. server.on{`request`, function{req, res} { 5. res.writeHead{200, {`Content~Tvpe`: `text/plain`}}; 6. res.write{`Hello World!`}; 7. res.end{}; 8. }}; 9. server.listen{4000}; l0. On line 1 we get the 'http' mooule. to which we call createServer line 3 to create an HTTF server. We then listen lor 'request' tvpe events. passing in a callback lunction that gets two arguments: the request object ano the response object. We can then use the response object to write back to the client. On line 5 we write a heaoer ContentTvpe: textplain ano the HTTF status 200 OK. On line o we replv the string "Hello Worlo" ano on line 7 we terminate the request. On line 9 we bino the server to the port !000. So. il vou run this script on nooe vou can then point vour browser to http:localhost:!000 ano vou shoulo see the "Hello Worlo" string on it. This example can be shorteneo to: Source in file: http/http_server_2.js l. require{`http`}.createServer{function{req, res} { 2. res.writeHead{200, {`Content~Tvpe`: `text/plain`}}; 3. res.end{`Hello World!`}; 4. }}.listen{4000}; Here we are giving up the intermeoiarv variables lor storing the http mooule since we onlv neeo to call it once ano the server since we onlv neeo to make it listen on port !000. Also. as a shortcut. the http.createServer lunction accepts a callback lunction that will be invokeo on everv request. There is one last shortcut here: the response.eno lunction can accept a string or buller which it will Hands-on Node HTTP 57/147 seno to the client belore enoing the request. The http.ServerRequest object When listening lor "request" events. the callback gets one ol these objects as the nrst argument. This object contains: req.ur| The URL ol the request. as a string. It ooes not contain the schema. hostname or port. but it contains evervthing alter that. You can trv this to analvze the url: Source in file: http/http_server_3.js l. require{`http`}.createServer{function{req, res} { 2. res.writeHead{200, {`Content~Tvpe`: `text/plain`}}; 3. res.end{req.url}; 4. }}.listen{4000}; ano connect to port !000 using a browser. Change the URL to see how it behaves. req.method This contains the HTTF methoo useo on the request. It can be. lor example. 'GET'. 'FOST'. 'DELETE' or anv other one. req.headers This contains an object with a propertv lor everv HTTF heaoer on the request. To analvze it vou can run this server: Source in file: http/http_server_4.js l. var util = require{`util`}; 2. 3. require{`http`}.createServer{function{req, res} { 4. res.writeHead{200, {`Content~Tvpe`: `text/plain`}}; 5. res.end{util.inspect{req.headers}}; 6. }}.listen{4000}; ano connect vour browser to port !000 to inspect the heaoers ol vour request. Here we are using util.inspect{}. an utilitv lunction that can be useo to analvze the properties ol anv object. Hands-on Node HTTP 58/147 req.headers properties are on lower-case. Ior instance. il the browser sent a "Cache- Control: max-age: 0" heaoer. req.headers will have a propertv nameo "cache-control" with the value "max-age: 0" this last one is untoucheo. The http.ServerResponse object The response object the secono argument lor the "request" event callback lunction is useo to replv to the client. With it vou can: Wr|te a header You can use res.writeHead{status, headers}. where heaoers is an object that contains a propertv lor everv heaoer vou want to seno. An example: Source in file: http/http_server_5.js l. var util = require{`util`}; 2. 3. require{`http`}.createServer{function{req, res} { 4. res.writeHead{200, { 5. `Content~Tvpe`: `text/plain`, 6. `Cache~Control`: `max~age=3600` 7. }}; 8. res.end{`Hello World!`}; 9. }}.listen{4000}; On this example we set 2 heaoers: one with "Content-Tvpe: textplain" ano another with "Cache- Control: max-age~3o00". Il vou save the above source cooe into http_server_5.js ano run it with: $ node http_server_5.js You can querv it bv using vour browser or using a commano-line HTTF client like curl: l. $ curl ~i http://localhost:4000 2. HTTP/l.l 200 OK 3. Content~Tvpe: text/plain 4. Cache~Control: max~age=3600 5. Connection: keep~alive 6. Transfer~Encoding: chunked 7. 8. Hello World! Change or set a header You can change a heaoer vou alreaov set or set a new one bv using Hands-on Node HTTP 59/147 res.setHeader{name, value}; This will onlv work il vou haven't alreaov sent a piece ol the boov bv using res.write. Remove a header You can remove a heaoer vou have alreaov set bv calling: res.removeHeader{name, value}; Again. this will onlv work il vou haven't alreaov sent a piece ol the boov bv using res.write. Wr|te a p|ece of the response body You can write a string: res.write{`Hello`}; or a an existing buller: l. var buf = new Buffer{`Hello World`}; 2. buf|01 = 45; 3. res.write{buffer}; This methoo can. as expecteo. be useo to replv ovnamicallv generateo strings or binarv nle. Replving with binarv oata will be covereo later. HTTP C||ent You can issue http requests using the "http" mooule. Nooe is specincallv oesigneo to be a server. but it can itsell call other external services ano act as a "glue" service. Or vou can simplv use it to run a simple http client script like this one: http.get(j Source in file: http/http_client_l.js Hands-on Node HTTP 60/147 This example uses http.get to make an HTTF GET request to the url http:www.google.com:80inoex.html. You can trv it bv saving it to a nle nameo http_client_1.js ano running: l. $ node http_client_l.js 2. 3. got response: 302 4. http.request(j Using http.request vou can make anv tvpe ol HTTF request: http.request{options, callback}; The options are: host: A oomain name or IF aooress ol the server to issue the request to. port: Fort ol remote server. method: A string specilving the HTTF request methoo. Fossible values: 'GET' oelault. 'FOST'. 'FUT'. ano 'DELETE'. path: Request path. Shoulo incluoe querv string ano lragments il anv. E.G. 'inoex.html?page~12' headers: An object containing request heaoers. The lollowing methoo makes it easv to seno boov values like when vou are uploaoing a nle or posting a lorm: Source in file: http/http_client_2.js Hands-on Node HTTP 61/147 l. var options = { 2. host: `www.google.com`, 3. port: 80, 4. path: `/upload`, 5. method: `POST` 6. }; 7. 8. var req = require{`http`}.request{options, function{res} { 9. console.log{`STATUS: ` + res.statusCode}; l0. console.log{`HEADERS: ` + JSON.stringifv{res.headers}}; ll. res.setEncoding{`utf8`}; l2. res.on{`data`, function {chunk} { l3. console.log{`BODY: ` + chunk}; l4. }}; l5. }}; l6. l7. // write data to request bodv l8. req.write{"data\n"}; l9. req.write{"data\n"}; 20. req.end{}; On lines 18 ano 19 we are writing the HTTF request boov oata two lines with the "oata" string ano on line 20 we are enoing the request. Onlv then the server replies ano the response callback gets activateo line 8. Then we wait lor the response. When it comes. we get a "response" event. which we are listening to on the callback lunction that starts on line 8. Bv then we onlv have the HTTF status ano heaoers reaov. which we print lines 9 no 10. Then we bino to "oata" events line 12. These happen when we get a chunk ol the response boov oata line 12. This mechanism can be useo to stream oata lrom a server. As long as the server keeps senoing boov chunks. we keep receiving them. HTTP Exerc|ses You can checkout the solutions at the eno ol this book. Exerc|se 1 Make an HTTF server that serves nles. The nle path is provioeo in the URL like this: http:localhost:!000pathtomvnle.txt Exerc|se 2 Hands-on Node HTTP 62/147 Make an HTTF server that outputs plain text with 100 new-line separateo unix timestamps everv secono. Exerc|se 3 Make an HTTF server that saves the request boov into a nle. Exerc|se 4 Make a script that accepts a nle name as nrst commano line argument ano uploaos this nle into the server built on the previous exercise. Hands-on Node HTTP 63/147
Michael Hartl - Learn Enough JavaScript To Be Dangerous - Write Programs, Publish Packages, and Develop Interactive Websites With JavaScript (2022, Addison-Wesley Professional) - Libgen - Li