table of contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · the node.js handbook the node...

189

Upload: others

Post on 04-Oct-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find
Page 2: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TableofContentsTheNode.jsHandbook

Introduction

IntroductiontoNode

AbriefhistoryofNode

HowtoinstallNode

HowmuchJavaScriptdoyouneedtoknowtouseNode?

DifferencesbetweenNodeandtheBrowser

v8

Basics

RunNode.jsscriptsfromthecommandline

HowtoexitfromaNode.jsprogram

Howtoreadenvironmentvariables

Nodehostingoptions

CommandLine

UsetheNodeREPL

Passargumentsfromthecommandline

Outputtothecommandline

Acceptinputfromthecommandline

Nodemodulesandnpm

ExposefunctionalityfromaNodefileusingexports

npm

Wheredoesnpminstallthepackages

Howtouseorexecuteapackageinstalledusingnpm

Thepackage.jsonfile

Thepackage-lock.jsonfile

Findtheinstalledversionofannpmpackage

Howtoinstallanolderversionofannpmpackage

HowtoupdatealltheNodedependenciestotheirlatestversion

Semanticversioningrules

Uninstallingnpmpackages

2

Page 3: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Globalorlocalpackages

npmdependenciesanddevDependencies

npx

Workingwiththeeventloop

Theeventloop

nextTick

setImmediate

Timers

Asynchronousprogramming

Callbacks

Promises

async/await

TheNodeEventEmitter

Networking

HTTP

HowHTTPRequestswork

BuildanHTTPserver

MakingHTTPrequests

Axios

Websockets

HTTPS,secureconnections

FileSystem

Filedescriptors

Filestats

Filepaths

Readingfiles

Writingfiles

Workingwithfolders

Someessentialcoremodules

Thefsmodule

Thepathmodule

Theosmodule

Theeventsmodule

3

Page 4: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thehttpmodule

Miscellaneous

Streams

WorkingwithMySQL

Differencebetweendevelopmentandproduction

4

Page 5: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheNode.jsHandbook

TheNodeHandbookfollowsthe80/20rule:learnin20%ofthetimethe80%ofatopic.

Ifindthisapproachgivesawell-roundedoverview.ThisbookdoesnottrytocovereverythingunderthesunrelatedtoNode.Ifyouthinksomespecifictopicshouldbeincluded,tellme.

YoucanreachmeonTwitter@flaviocopes.

Ihopethecontentsofthisbookwillhelpyouachievewhatyouwant:learnthebasicsNode.js.

ThisbookiswrittenbyFlavio.Ipublishwebdevelopmenttutorialseverydayonmywebsiteflaviocopes.com.

Enjoy!

TheNode.jsHandbook

5

Page 6: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

IntroductiontoNodeThispostisagettingstartedguidetoNode.js,theserver-sideJavaScriptruntimeenvironment.Node.jsisbuiltontopoftheGoogleChromeV8JavaScriptengine,andit'smainlyusedtocreatewebservers-butit'snotlimitedtothat

OverviewThebestfeaturesofNode.js

FastSimpleJavaScriptV8AsynchronousplatformAhugenumberoflibraries

AnexampleNode.jsapplicationNode.jsframeworksandtools

OverviewNode.jsisaruntimeenvironmentforJavaScriptthatrunsontheserver.

Node.jsisopensource,cross-platform,andsinceitsintroductionin2009,itgothugelypopularandnowplaysasignificantroleinthewebdevelopmentscene.IfGitHubstarsareonepopularityindicationfactor,having46000+starsmeansbeingverypopular.

IntroductiontoNode

6

Page 7: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Node.jsisbuiltontopoftheGoogleChromeV8JavaScriptengine,andit'smainlyusedtocreatewebservers-butit'snotlimitedtothat.

ThebestfeaturesofNode.js

Fast

OneofthemainsellingpointsofNode.jsisspeed.JavaScriptcoderunningonNode.js(dependingonthebenchmark)canbetwiceasfastthancompiledlanguageslikeCorJava,andordersofmagnitudefasterthaninterpretedlanguageslikePythonorRuby,becauseofitsnon-blockingparadigm.

Simple

Node.jsissimple.Extremelysimple,actually.

JavaScript

Node.jsrunsJavaScriptcode.ThismeansthatmillionsoffrontenddevelopersthatalreadyuseJavaScriptinthebrowserareabletoruntheserver-sidecodeandfrontend-sidecodeusingthesameprogramminglanguagewithouttheneedtolearnacompletelydifferenttool.

Theparadigmsareallthesame,andinNode.jsthenewECMAScriptstandardscanbeusedfirst,asyoudon'thavetowaitforallyouruserstoupdatetheirbrowsers-youdecidewhichECMAScriptversiontousebychangingtheNode.jsversion.

V8

IntroductiontoNode

7

Page 8: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

RunningontheGoogleV8JavaScriptengine,whichisOpenSource,Node.jsisabletoleveragetheworkofthousandsofengineersthatmade(andwillcontinuetomake)theChromeJavaScriptruntimeblazingfast.

Asynchronousplatform

Intraditionalprogramminglanguages(C,Java,Python,PHP)allinstructionsareblockingbydefaultunlessyouexplicitly"optin"toperformasynchronousoperations.IfyouperformanetworkrequesttoreadsomeJSON,theexecutionofthatparticularthreadisblockeduntiltheresponseisready.

JavaScriptallowstocreateasynchronousandnon-blockingcodeinaverysimpleway,byusingasinglethread,callbackfunctionsandevent-drivenprogramming.Everytimeanexpensiveoperationoccurs,wepassacallbackfunctionthatwillbecalledoncewecancontinuewiththeprocessing.We'renotwaitingforthattofinishbeforegoingonwiththerestoftheprogram.

Suchmechanismderivesfromthebrowser.Wecan'twaituntilsomethingloadsfromanAJAXrequestbeforebeingabletointerceptclickeventsonthepage.Itallmusthappeninrealtimetoprovideagoodexperiencetotheuser.

Ifyou'vecreatedanonclickhandlerforawebpageyou'vealreadyusedasynchronousprogrammingtechniqueswitheventlisteners.

ThisallowsNode.jstohandlethousandsofconcurrentconnectionswithasingleserverwithoutintroducingtheburdenofmanagingthreadsconcurrency,whichwouldbeamajorsourceofbugs.

Nodeprovidesnon-blockingI/Oprimitives,andgenerally,librariesinNode.jsarewrittenusingnon-blockingparadigms,makingablockingbehavioranexceptionratherthanthenormal.

IntroductiontoNode

8

Page 9: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WhenNode.jsneedstoperformanI/Ooperation,likereadingfromthenetwork,accessadatabaseorthefilesystem,insteadofblockingthethreadNode.jswillsimplyresumetheoperationswhentheresponsecomesback,insteadofwastingCPUcycleswaiting.

Ahugenumberoflibraries

npmwithitssimplestructurehelpedtheecosystemofnode.jsproliferateandnowthenpmregistryhostsalmost500.000opensourcepackagesyoucanfreelyuse.

AnexampleNode.jsapplicationThemostcommonexampleHelloWorldofNode.jsisawebserver:

consthttp=require('http')

consthostname='127.0.0.1'

constport=3000

constserver=http.createServer((req,res)=>{

res.statusCode=200

res.setHeader('Content-Type','text/plain')

res.end('HelloWorld\n')

})

server.listen(port,hostname,()=>{

console.log(`Serverrunningathttp://${hostname}:${port}/`)

})

Torunthissnippet,saveitasa server.jsfileandrun nodeserver.jsinyourterminal.

ThiscodefirstincludestheNode.js httpmodule.

Node.jshasanamazingstandardlibrary,includingafirst-classsupportfornetworking.

The createServer()methodof httpcreatesanewHTTPserverandreturnsit.

Theserverissettolistenonthespecifiedportandhostname.Whentheserverisready,thecallbackfunctioniscalled,inthiscaseinformingusthattheserverisrunning.

Wheneveranewrequestisreceived,the requesteventiscalled,providingtwoobjects:arequest(an http.IncomingMessageobject)andaresponse(an http.ServerResponseobject).

Those2objectsareessentialtohandletheHTTPcall.

Thefirstprovidestherequestdetails.Inthissimpleexample,thisisnotused,butyoucouldaccesstherequestheadersandrequestdata.

IntroductiontoNode

9

Page 10: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thesecondisusedtoreturndatatothecaller.

Inthiscasewith

res.statusCode=200

wesetthestatusCodepropertyto200,toindicateasuccessfulresponse.

WesettheContent-Typeheader:

res.setHeader('Content-Type','text/plain')

andweendclosetheresponse,addingthecontentasanargumentto end():

res.end('HelloWorld\n')

Node.jsframeworksandtoolsNode.jsisalow-levelplatform,andtomakethingseasierandmoreinterestingfordevelopersthousandsoflibrarieswerebuiltuponNode.js.

Manyofthoseestablishedovertimeaspopularoptions.Hereisanon-comprehensivelisttotheonesIconsiderveryrelevantandworthlearning:

Express,oneofthemostsimpleyetpowerfulwaystocreateawebserver.Itsminimalistapproach,unopinionated,focusedonthecorefeaturesofaserver,iskeytoitssuccess.Meteor,anincrediblypowerfulfull-stackframework,poweringyouwithanisomorphicapproachtobuildingappswithJavaScript,sharingcodeontheclientandtheserver.Onceanoff-the-shelftoolthatprovidedeverything,nowintegrateswithfrontendlibsReact,VueandAngular.Canbeusedtocreatemobileappsaswell.koa,builtbythesameteambehindExpress,aimstobeevensimplerandsmaller,buildingontopofyearsofknowledge.Thenewprojectbornoutoftheneedtocreateincompatiblechangeswithoutdisruptingtheexistingcommunity.Next.js,aframeworktorenderserver-siderenderedReactapplications.Micro,averylightweightservertocreateasynchronousHTTPmicroservices.Socket.io,areal-timecommunicationenginetobuildnetworkapplications.

IntroductiontoNode

10

Page 11: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

AbriefhistoryofNodeAlookbackonthehistoryofNode.jsfrom2009totoday

Believeitornot,Node.jsisjust9yearsold.

Incomparison,JavaScriptis23yearsoldandthewebasweknowit(aftertheintroductionofMosaic)is25yearsold.

9yearsissuchalittleamountoftimeforatechnology,butNode.jsseemstohavebeenaroundforever.

I'vehadthepleasuretoworkwithNodesincetheearlydayswhenitwasjust2yearsold,anddespitethelittleinformationavailable,youcouldalreadyfeelitwasahugething.

Inthispost,IwanttodrawthebigpictureofNodeinitshistory,toputthingsinperspective.

Alittlebitofhistory2009201020112012201320142015201620172018

AlittlebitofhistoryJavaScriptisaprogramminglanguagethatwascreatedatNetscapeasascriptingtooltomanipulatewebpagesinsidetheirbrowser,NetscapeNavigator.

PartofthebusinessmodelofNetscapewastosellWebServers,whichincludedanenvironmentcalledNetscapeLiveWire,whichcouldcreatedynamicpagesusingserver-sideJavaScript.Sotheideaofserver-sideJavaScriptwasnotintroducedbyNode.js,butit'soldjustlikeJavaScript-butatthetimeitwasnotsuccessful.

OnekeyfactorthatledtotheriseofNode.jswastiming.JavaScriptsinceafewyearswasstartingbeingconsideredaseriouslanguage,thanksforthe"Web2.0"applicationsthatshowedtheworldwhatamodernexperienceonthewebcouldbelike(thinkGoogleMapsor

AbriefhistoryofNode

11

Page 12: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

GMail).

TheJavaScriptenginesperformancebarraisedconsiderablythankstothebrowsercompetitionbattle,whichisstillgoingstrong.Developmentteamsbehindeachmajorbrowserworkhardeverydaytogiveusbetterperformance,whichisahugewinforJavaScriptasaplatform.V8,theenginethatNode.jsusesunderthehood,isoneofthoseandinparticularit'stheChromeJSengine.

Butofcourse,Node.jsisnotpopularjustbecauseofpureluckortiming.ItintroducedmuchinnovativethinkingonhowtoprograminJavaScriptontheserver.

2009Node.jsisbornThefirstformofnpmiscreated

2010ExpressisbornSocket.ioisborn

2011npmhits1.0BigcompaniesstartadoptingNode:LinkedIn,UberHapiisborn

2012Adoptioncontinuesveryrapidly

2013FirstbigbloggingplatformusingNode:GhostKoaisborn

2014Bigdrama:IO.jsisamajorforkofNode.js,withthegoalofintroducingES6supportandmovefaster

2015

AbriefhistoryofNode

12

Page 13: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheNode.jsFoundationisbornIO.jsismergedbackintoNode.jsnpmintroducesprivatemodulesNode4(no1,2,3versionswerepreviouslyreleased)

2016TheleftpadincidentYarnisbornNode6

2017npmfocusesmoreonsecurityNode8HTTP/2V8introducesNodeinitstestingsuite,officiallymakingNodeatargetfortheJSengine,inadditiontoChrome3billionnpmdownloadseveryweek

2018Node10ESmodules.mjsexperimentalsupport

AbriefhistoryofNode

13

Page 14: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtoinstallNodeHowyoucaninstallNode.jsonyoursystem:apackagemanager,theofficialwebsiteinstallerornvm

Node.jscanbeinstalledindifferentways.Thisposthighlightsthemostcommonandconvenientones.

Officialpackagesforallthemajorplatformsareavailableathttps://nodejs.org/en/download/.

OneveryconvenientwaytoinstallNode.jsisthroughapackagemanager.Inthiscase,everyoperatingsystemhasitsown.

OnmacOS,Homebrewisthede-factostandard,and-onceinstalled-allowstoinstallNode.jsveryeasily,byrunningthiscommandintheCLI:

brewinstallnode

OtherpackagemanagersforLinuxandWindowsarelistedinhttps://nodejs.org/en/download/package-manager/

nvmisapopularwaytorunNode.ItallowsyoutoeasilyswitchtheNodeversion,andinstallnewversionstotryandeasilyrollbackifsomethingbreaks,forexample.

ItisalsoveryusefultotestyourcodewitholdNodeversions.

Seehttps://github.com/creationix/nvmformoreinformationaboutthisoption.

Mysuggestionistousetheofficialinstallerifyouarejuststartingoutandyoudon'tuseHomebrewalready,otherwise,Homebrewismyfavoritesolution.

Inanycase,whenNodeisinstalledyou'llhaveaccesstothe nodeexecutableprograminthecommandline.

HowtoinstallNode

14

Page 15: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowmuchJavaScriptdoyouneedtoknowtouseNode?IfyouarejuststartingoutwithJavaScript,howmuchdeeplydoyouneedtoknowthelanguage?

Asabeginner,it'shardtogettoapointwhereyouareconfidentenoughinyourprogrammingabilities.

Whilelearningtocode,youmightalsobeconfusedatwheredoesJavaScriptend,andwhereNode.jsbegins,andviceversa.

IwouldrecommendyoutohaveagoodgraspofthemainJavaScriptconceptsbeforedivingintoNode.js:

LexicalStructureExpressionsTypesVariablesFunctionsthisArrowFunctionsLoopsLoopsandScopeArraysTemplateLiteralsSemicolonsStrictModeECMAScript6,2016,2017

Withthoseconceptsinmind,youarewellonyourroadtobecomeaproficientJavaScriptdeveloper,inboththebrowserandinNode.js.

Thefollowingconceptsarealsokeytounderstandasynchronousprogramming,whichisonefundamentalpartofNode.js:

AsynchronousprogrammingandcallbacksTimersPromisesAsyncandAwaitClosuresTheEventLoop

HowmuchJavaScriptdoyouneedtoknowtouseNode?

15

Page 16: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

LuckilyIwroteafreeebookthatexplainsallthosetopics,andit'scalledJavaScriptFundamentals.It'sthemostcompactresourceyou'llfindtolearnallofthis.

Youcanfindtheebookatthebottomofthispage:https://flaviocopes.com/javascript/.

HowmuchJavaScriptdoyouneedtoknowtouseNode?

16

Page 17: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

DifferencesbetweenNodeandtheBrowserHowwritingJavaScriptapplicationinNode.jsdiffersfromprogrammingfortheWebinsidethebrowser

BoththebrowserandNodeuseJavaScriptastheirprogramminglanguage.

BuildingappsthatruninthebrowserisacompletelydifferentthingthanbuildingaNode.jsapplication.

Despitethefactthatit'salwaysJavaScript,therearesomekeydifferencesthatmaketheexperienceradicallydifferent.

AsafrontenddeveloperthatwritesNodeappshaveahugeadvantage-thelanguageisstillthesame.

Youhaveahugeopportunitybecauseweknowhowharditistofully,deeplylearnaprogramminglanguage,andbyusingthesamelanguagetoperformallyourworkontheweb-bothontheclientandontheserver,you'reinauniquepositionofadvantage.

Whatchangesistheecosystem.

Inthebrowser,mostofthetimewhatyouaredoingisinteractingwiththeDOM,orotherWebPlatformAPIslikeCookies.ThosedonotexistinNode,ofcourse.Youdon'thavethedocument, windowandalltheotherobjectsthatareprovidedbythebrowser.

Andinthebrowser,wedon'thavealltheniceAPIsthatNode.jsprovidesthroughitsmodules,likethefilesystemaccessfunctionality.

AnotherbigdifferenceisthatinNode.jsyoucontroltheenvironment.Unlessyouarebuildinganopensourceapplicationthatanyonecandeployanywhere,youknowwhichversionofNodeyouwillruntheapplicationon.Comparedtothebrowserenvironment,whereyoudon'tgettheluxurytochoosewhatbrowseryourvisitorswilluse,thisisveryconvenient.

ThismeansthatyoucanwriteallthemodernES6-7-8-9JavaScriptthatyourNodeversionsupports.

SinceJavaScriptmovessofast,butbrowserscanbeabitslowandusersabitslowtoupgrade,sometimesontheweb,youarestucktouseolderJavaScript/ECMAScriptreleases.

YYoucanuseBabeltotransformyourcodetobeES5-compatiblebeforeshippingittothebrowser,butinNode,youwon'tneedthat.

AnotherdifferenceisthatNodeusestheCommonJSmodulesystem,whileinthebrowserwearestartingtoseetheESModulesstandardbeingimplemented.

DifferencesbetweenNodeandtheBrowser

17

Page 18: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Inpractice,thismeansthatforthetimebeingyouuse require()inNodeand importinthebrowser.

DifferencesbetweenNodeandtheBrowser

18

Page 19: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

v8V8isthenameoftheJavaScriptenginethatpowersGoogleChrome.It'sthethingthattakesourJavaScriptandexecutesitwhilebrowsingwithChrome.V8providestheruntimeenvironmentinwhichJavaScriptexecutes.TheDOMandtheotherWebPlatformAPIsareprovidedbythebrowser.

V8isthenameoftheJavaScriptenginethatpowersGoogleChrome.It'sthethingthattakesourJavaScriptandexecutesitwhilebrowsingwithChrome.

V8providestheruntimeenvironmentinwhichJavaScriptexecutes.TheDOM,andtheotherWebPlatformAPIsareprovidedbythebrowser.

ThecoolthingisthattheJavaScriptengineisindependentbythebrowserinwhichit'shosted.ThiskeyfeatureenabledtheriseofNode.js.V8waschosenforbeingtheenginechosenbyNode.jsbackin2009,andasthepopularityofNode.jsexploded,V8becametheenginethatnowpowersanincredibleamountofserver-sidecodewritteninJavaScript.

TheNode.jsecosystemishugeandthankstoitV8alsopowersdesktopapps,withprojectslikeElectron.

v8

19

Page 20: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

OtherJSenginesOtherbrowsershavetheirownJavaScriptengine:

FirefoxhasSpidermonkeySafarihasJavaScriptCore(alsocalledNitro)EdgehasChakra

andmanyothersexistaswell.

AllthoseenginesimplementtheECMAES-262standard,alsocalledECMAScript,thestandardusedbyJavaScript.

ThequestforperformanceV8iswritteninC++,andit'scontinuouslyimproved.ItisportableandrunsonMac,Windows,Linuxandseveralothersystems.

InthisV8introduction,IwillignoretheimplementationdetailsofV8:theycanbefoundonmoreauthoritativesites(e.g.theV8officialsite),andtheychangeovertime,oftenradically.

V8isalwaysevolving,justliketheotherJavaScriptenginesaround,tospeeduptheWebandtheNode.jsecosystem.

Ontheweb,thereisaraceforperformancethat'sbeengoingonforyears,andwe(asusersanddevelopers)benefitalotfromthiscompetitionbecausewegetfasterandmoreoptimizedmachinesyearafteryear.

CompilationJavaScriptisgenerallyconsideredaninterpretedlanguage,butmodernJavaScriptenginesnolongerjustinterpretJavaScript,theycompileit.

Thishappenssince2009whentheSpiderMonkeyJavaScriptcompilerwasaddedtoFirefox3.5,andeveryonefollowedthisidea.

JavScriptisinternallycompiledbyV8withjust-in-time(JIT)compilationtospeeduptheexecution.

Thismightseemcounter-intuitive,butsincetheintroductionofGoogleMapsin2004,JavaScripthasevolvedfromalanguagethatwasgenerallyexecutingafewdozensoflinesofcodetocompleteapplicationswiththousandstohundredsofthousandsoflinesrunninginthebrowser.

v8

20

Page 21: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Ourapplicationsnowcanrunforhoursinsideabrowser,ratherthanbeingjustafewformvalidationrulesorsimplescripts.

Inthisnewworld,compilingJavaScriptmakesperfectsensebecausewhileitmighttakealittlebitmoretohavetheJavaScriptready,oncedoneit'sgoingtobemuchmoreperformantthatpurelyinterpretedcode.

v8

21

Page 22: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

RunNode.jsscriptsfromthecommandlineHowtorunanyNode.jsscriptfromtheCLI

TheusualwaytorunaNodeprogramistocallthe nodegloballyavailablecommand(onceyouinstallNode)andpassthenameofthefileyouwanttoexecute.

IfyourmainNodeapplicationfileisin app.js,youcancallitbytyping

nodeapp.js

RunNode.jsscriptsfromthecommandline

22

Page 23: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtoexitfromaNode.jsprogramLearnhowtoterminateaNode.jsappinthebestpossibleway

TherearevariouswaystoterminateaNode.jsapplication.

Whenrunningaprogramintheconsoleyoucancloseitwith ctrl-C,butwhatIwanttodiscusshereisprogrammaticallyexiting.

Let'sstartwiththemostdrasticone,andseewhyyou'rebetteroffnotusingit.

The processcoremoduleisprovidesahandymethodthatallowsyoutoprogrammaticallyexitfromaNode.jsprogram: process.exit().

WhenNode.jsrunsthisline,theprocessisimmediatelyforcedtoterminate.

Thismeansthatanycallbackthat'spending,anynetworkrequeststillbeingsent,anyfilesystemaccess,orprocesseswritingto stdoutor stderr-allisgoingtobeungracefullyterminatedrightaway.

Ifthisisfineforyou,youcanpassanintegerthatsignalstheoperatingsystemtheexitcode:

process.exit(1)

Bydefaulttheexitcodeis 0,whichmeanssuccess.Differentexitcodeshavedifferentmeaning,whichyoumightwanttouseinyourownsystemtohavetheprogramcommunicatetootherprograms.

Youcanreadmoreonexitcodesathttps://nodejs.org/api/process.html#process_exit_codes

Youcanalsosetthe process.exitCodeproperty:

process.exitCode=1

andwhentheprogramwilllaterend,Nodewillreturnthatexitcode.

Aprogramwillgracefullyexitwhenalltheprocessingisdone.

ManytimeswithNodewestartservers,likethisHTTPserver:

constexpress=require('express')

constapp=express()

app.get('/',(req,res)=>{

res.send('Hi!')

})

HowtoexitfromaNode.jsprogram

23

Page 24: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

app.listen(3000,()=>console.log('Serverready'))

Thisprogramisnevergoingtoend.Ifyoucall process.exit(),anycurrentlypendingorrunningrequestisgoingtobeaborted.Thisisnotnice.

InthiscaseyouneedtosendthecommandaSIGTERMsignal,andhandlethatwiththeprocesssignalhandler:

Note: processdoesnotrequirea"require",it'sautomaticallyavailable.

constexpress=require('express')

constapp=express()

app.get('/',(req,res)=>{

res.send('Hi!')

})

constserver=app.listen(3000,()=>console.log('Serverready'))

process.on('SIGTERM',()=>{

server.close(()=>{

console.log('Processterminated')

})

})

Whataresignals?SignalsareaPOSIXintercommunicationsystem:anotificationsenttoaprocessinordertonotifyitofaneventthatoccurred.

SIGKILListhesignalsthattellsaprocesstoimmediatelyterminate,andwouldideallyactlikeprocess.exit().

SIGTERMisthesignalsthattellsaprocesstogracefullyterminate.Itisthesignalthat'ssentfromprocessmanagerslike upstartor supervisordandmanyothers.

Youcansendthissignalfrominsidetheprogram,inanotherfunction:

process.kill(process.pid,'SIGTERM')

OrfromanotherNode.jsrunningprogram,oranyotherapprunninginyoursystemthatknowsthePIDoftheprocessyouwanttoterminate.

HowtoexitfromaNode.jsprogram

24

Page 25: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtoreadenvironmentvariablesLearnhowtoreadandmakeuseofenvironmentvariablesinaNode.jsprogram

The processcoremoduleofNodeprovidesthe envpropertywhichhostsalltheenvironmentvariablesthatweresetatthemomenttheprocesswasstarted.

HereisanexamplethataccessestheNODE_ENVenvironmentvariable,whichissettodevelopmentbydefault.

Note: processdoesnotrequirea"require",it'sautomaticallyavailable.

process.env.NODE_ENV//"development"

Settingitto"production"beforethescriptrunswilltellNodethatthisisaproductionenvironment.

Inthesamewayyoucanaccessanycustomenvironmentvariableyouset.

Howtoreadenvironmentvariables

25

Page 26: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

NodehostingoptionsANode.jsapplicationcanbehostedinalotofplaces,dependingonyourneeds.Thisisalistofallthevariousoptionsyouhaveatyourdisposal

Hereisanon-exhaustivelistoftheoptionsyoucanexplorewhenyouwanttodeployyourappandmakeitpubliclyaccessible.

Iwilllisttheoptionsfromsimplestandconstrainedtomorecomplexandpowerful.

Simplestoptionever:localtunnelZeroconfigurationdeployments

GlitchCodepen

ServerlessPAAS

ZeitNowNanoboxHerokuMicrosoftAzureGoogleCloudPlatform

VirtualPrivateServerBaremetal

Simplestoptionever:localtunnelEvenifyouhaveadynamicIP,oryou'reunderaNAT,youcandeployyourappandservetherequestsrightfromyourcomputerusingalocaltunnel.

Thisoptionissuitedforsomequicktesting,demoaproductorsharingofanappwithaverysmallgroupofpeople.

Averynicetoolforthis,availableonallplatforms,isngrok.

Usingit,youcanjusttype ngrokPORTandthePORTyouwantisexposedtotheinternet.Youwillgetangrok.iodomain,butwithapaidsubscriptionyoucangetacustomURLaswellasmoresecurityoptions(rememberthatyouareopeningyourmachinetothepublicInternet).

Anotherserviceyoucanuseishttps://github.com/localtunnel/localtunnel

Zeroconfigurationdeployments

Nodehostingoptions

26

Page 27: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Glitch

Glitchisaplaygroundandawaytobuildyourappsfasterthanever,andseethemliveontheirownglitch.comsubdomain.Youcannotcurrentlyhaveaacustomdomain,andthereareafewrestrictionsinplace,butit'sreallygreattoprototype.Itlooksfun(andthisisaplus),andit'snotadumbeddownenvironment-yougetallthepowerofNode.js,aCDN,securestorageforcredentials,GitHubimport/exportandmuchmore.

ProvidedbythecompanybehindFogBugzandTrello(andco-creatorsofStackOverflow).

Iuseitalotfordemopurposes.

Codepen

Codepenisanamazingplatformandcommunity.Youcancreateaprojectwithmultiplefiles,anddeployitwithacustomdomain.

ServerlessAwaytopublishyourapps,andhavenoserveratalltomanage,isServerless.Serverlessisaparadigmwhereyoupublishyourappsasfunctions,andtheyrespondonanetworkendpoint(alsocalledFAAS-FunctionsAsAService).

Toverypopularsolutionsare

ServerlessFrameworkStandardLibrary

TheybothprovideanabstractionlayertopublishingonAWSLambdaandotherFAASsolutionsbasedonAzureortheGoogleCloudoffering.

PAASPAASstandsforPlatformAsAService.Theseplatformstakeawayalotofthingsyoushouldotherwiseworryaboutwhendeployingyourapplication.

ZeitNow

Zeitisaninterestingoption.Youjusttype nowinyourterminal,andittakescareofdeployingyourapplication.Thereisafreeversionwithlimitations,andthepaidversionismorepowerful.Yousimplyforgetthatthere'saserver,youjustdeploytheapp.

Nodehostingoptions

27

Page 28: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Nanobox

Nanobox

Heroku

Herokuisanamazingplatform.

ThisisagreatarticleongettingstartedwithNode.jsonHeroku.

MicrosoftAzure

AzureistheMicrosoftCloudoffering.

CheckouthowtocreateaNode.jswebappinAzure.

GoogleCloudPlatform

GoogleCloudisanamazingstructureforyourapps.

TheyhaveagoodNode.jsDocumentationSection

VirtualPrivateServerInthissectionyoufindtheusualsuspects,orderedfrommoreuserfriendlytolessuserfriendly:

DigitalOceanLinodeAmazonWebServices,inparticularImentionAmazonElasticBeanstalkasitabstractsawayalittlebitthecomplexityofAWS.

SincetheyprovideanemptyLinuxmachineonwhichyoucanwork,thereisnospecifictutorialforthese.

TherearelotsmoreoptionsintheVPScategory,thosearejusttheonesIusedandIwouldrecommend.

BaremetalAnothersolutionistogetabaremetalserver,installaLinuxdistribution,connectittotheinternet(orrentonemonthly,likeyoucandousingtheVultrBareMetalservice)

Nodehostingoptions

28

Page 29: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Nodehostingoptions

29

Page 30: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

UsetheNodeREPLREPLstandsforRead-Evaluate-Print-Loop,andit'sagreatwaytoexploretheNodefeaturesinaquickway

The nodecommandistheoneweusetorunourNode.jsscripts:

nodescript.js

Ifweomitthefilename,weuseitinREPLmode:

node

Ifyoutryitnowinyourterminal,thisiswhathappens:

❯node>

thecommandstaysinidlemodeandwaitsforustoentersomething.

Tip:ifyouareunsurehowtoopenyourterminal,google"Howtoopenterminalon".

TheREPLiswaitingforustoentersomeJavaScriptcode,tobemoreprecise.

Startsimpleandenter

>console.log('test')

test

undefined

>

Thefirstvalue, test,istheoutputwetoldtheconsoletoprint,thenwegetundefinedwhichisthereturnvalueofrunning console.log().

WecannowenteranewlineofJavaScript.

UsethetabtoautocompleteThecoolthingabouttheREPListhatit'sinteractive.

Asyouwriteyourcode,ifyoupressthe tabkeytheREPLwilltrytoautocompletewhatyouwrotetomatchavariableyoualreadydefinedorapredefinedone.

UsetheNodeREPL

30

Page 31: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ExploringJavaScriptobjectsTryenteringthenameofaJavaScriptclass,like Number,addadotandpress tab.

TheREPLwillprintallthepropertiesandmethodsyoucanaccessonthatclass:

ExploreglobalobjectsYoucaninspecttheglobalsyouhaveaccesstobytyping global.andpressing tab:

UsetheNodeREPL

31

Page 32: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

The_specialvariableIfaftersomecodeyoutype _,thatisgoingtoprinttheresultofthelastoperation.

DotcommandsTheREPLhassomespecialcommands,allstartingwithadot ..Theyare

.help:showsthedotcommandshelp.editor:enableseditormore,towritemultilineJavaScriptcodewithease.Onceyouareinthismode,enterctrl-Dtorunthecodeyouwrote..break:wheninputtingamulti-lineexpression,enteringthe.breakcommandwillabortfurtherinput.Sameaspressingctrl-C..clear:resetstheREPLcontexttoanemptyobjectandclearsanymulti-lineexpression

UsetheNodeREPL

32

Page 33: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

currentlybeinginput..load:loadsaJavaScriptfile,relativetothecurrentworkingdirectory.save:savesallyouenteredintheREPLsessiontoafile(specifythefilename).exit:existstherepl(sameaspressingctrl-Ctwotimes)

TheREPLknowswhenyouaretypingamulti-linestatementwithouttheneedtoinvoke.editor.

Forexampleifyoustarttypinganiterationlikethis:

[1,2,3].forEach(num=>{

andyoupress enter,theREPLwillgotoanewlinethatstartswith3dots,indicatingyoucannowcontinuetoworkonthatblock.

...console.log(num)

...})

Ifyoutype .breakattheendofaline,themultilinemodewillstopandthestatementwillnotbeexecuted.

UsetheNodeREPL

33

Page 34: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

PassargumentsfromthecommandlineHowtoacceptargumentsinaNode.jsprogrampassedfromthecommandline

YoucanpassanynumberofargumentswheninvokingaNode.jsapplicationusing

nodeapp.js

Argumentscanbestandaloneorhaveakeyandavalue.

Forexample:

nodeapp.jsflavio

or

nodeapp.jsname=flavio

ThischangeshowyouwillretrievethisvalueintheNodecode.

Thewayyouretrieveitisusingthe processobjectbuiltintoNode.

Itexposesan argvproperty,whichisanarraythatcontainsallthecommandlineinvocationarguments.

Thefirstargumentisthefullpathofthe nodecommand.

Thesecondelementisthefullpathofthefilebeingexecuted.

Alltheadditionalargumentsarepresentfromthethirdpositiongoingforward.

Youcaniterateoverallthearguments(includingthenodepathandthefilepath)usingaloop:

process.argv.forEach((val,index)=>{

console.log(`${index}:${val}`)

})

Youcangetonlytheadditionalargumentsbycreatinganewarraythatexcludesthefirst2params:

constargs=process.argv.slice(2)

Passargumentsfromthecommandline

34

Page 35: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Ifyouhaveoneargumentwithoutanindexname,likethis:

nodeapp.jsflavio

youcanaccessitusing

constargs=process.argv.slice(2)

args[0]

Inthiscase:

nodeapp.jsname=flavio

args[0]is name=flavio,andyouneedtoparseit.Thebestwaytodosoisbyusingtheminimistlibrary,whichhelpsdealingwitharguments:

constargs=require('minimist')(process.argv.slice(2))

args['name']//flavio

Passargumentsfromthecommandline

35

Page 36: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

OutputtothecommandlineHowtoprinttothecommandlineconsoleusingNode,fromthebasicconsole.logtomorecomplexscenarios

BasicoutputusingtheconsolemoduleCleartheconsoleCountingelementsPrintthestacktraceCalculatethetimespentstdoutandstderrColortheoutputCreateaprogressbar

BasicoutputusingtheconsolemoduleNodeprovidesa consolemodulewhichprovidestonsofveryusefulwaystointeractwiththecommandline.

Itisbasicallythesameasthe consoleobjectyoufindinthebrowser.

Themostbasicandmostusedmethodis console.log(),whichprintsthestringyoupasstoittotheconsole.

Ifyoupassanobject,itwillrenderitasastring.

Youcanpassmultiplevariablesto console.log,forexample:

constx='x'

consty='y'

console.log(x,y)

andNodewillprintboth.

Wecanalsoformatprettyphrasesbypassingvariablesandaformatspecifier.

Forexample:

console.log('My%shas%dyears','cat',2)

%sformatavariableasastring%dor %iformatavariableasaninteger

Outputtothecommandline

36

Page 37: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

%fformatavariableasafloatingpointnumber%Ousedtoprintanobjectrepresentation

Example:

console.log('%O',Number)

Cleartheconsoleconsole.clear()clearstheconsole(thebehaviormightdependontheconsoleused)

Countingelementsconsole.count()isahandymethod.

Takethiscode:

constx=1

consty=2

constz=3

console.count(

'Thevalueofxis'+x+'andhasbeenchecked..howmanytimes?'

)

console.count(

'Thevalueofxis'+x+'andhasbeenchecked..howmanytimes?'

)

console.count(

'Thevalueofyis'+y+'andhasbeenchecked..howmanytimes?'

)

Whathappensisthatcountwillcountthenumberoftimesastringisprinted,andprintthecountnexttoit:

Youcanjustcountapplesandoranges:

constoranges=['orange','orange']

constapples=['justoneapple']

oranges.forEach(fruit=>{

console.count(fruit)

})

apples.forEach(fruit=>{

console.count(fruit)

})

Outputtothecommandline

37

Page 38: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

PrintthestacktraceTheremightbecaseswhereit'susefultoprintthecallstacktraceofafunction,maybetoanswerthequestionhowdidyoureachthatpartofthecode?

Youcandosousing console.trace():

constfunction2=()=>console.trace()

constfunction1=()=>function2()

function1()

Thiswillprintthestacktrace.Thisiswhat'sprintedifItrythisintheNodeREPL:

Trace

atfunction2(repl:1:33)

atfunction1(repl:1:25)

atrepl:1:1

atContextifyScript.Script.runInThisContext(vm.js:44:33)

atREPLServer.defaultEval(repl.js:239:29)

atbound(domain.js:301:14)

atREPLServer.runBound[aseval](domain.js:314:12)

atREPLServer.onLine(repl.js:440:10)

atemitOne(events.js:120:20)

atREPLServer.emit(events.js:210:7)

CalculatethetimespentYoucaneasilycalculatehowmuchtimeafunctiontakestorun,using time()and timeEnd()

constdoSomething=()=>console.log('test')

constmeasureDoingSomething=()=>{

console.time('doSomething()')

//dosomething,andmeasurethetimeittakes

doSomething()

console.timeEnd('doSomething()')

}

measureDoingSomething()

stdoutandstderrAswesawconsole.logisgreatforprintingmessagesintheConsole.Thisiswhat'scalledthestandardoutput,or stdout.

console.errorprintstothe stderrstream.

Outputtothecommandline

38

Page 39: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Itwillnotappearintheconsole,butitwillappearintheerrorlog.

ColortheoutputYoucancolortheoutputofyourtextintheconsolebyusingescapesequences.Anescapesequenceisasetofcharactersthatidentifiesacolor.

Example:

console.log('\x1b[33m%s\x1b[0m','hi!')

YoucantrythatintheNodeREPL,anditwillprint hi!inyellow.

However,thisisthelow-levelwaytodothis.Thesimplestwaytogoaboutcoloringtheconsoleoutputisbyusingalibrary.Chalkissuchalibrary,andinadditiontocoloringitalsohelpswithotherstylingfacilities,likemakingtextbold,italicorunderlined.

Youinstallitwith npminstallchalk,thenyoucanuseit:

constchalk=require('chalk')

console.log(chalk.yellow('hi!'))

Using chalk.yellowismuchmoreconvenientthantryingtoremembertheescapecodes,andthecodeismuchmorereadable.

ChecktheprojectlinkIpostedaboveformoreusageexamples.

CreateaprogressbarProgressisanawesomepackagetocreateaprogressbarintheconsole.Installitusing npminstallprogress

Thissnippetcreatesa10-stepprogressbar,andevery100msonestepiscompleted.Whenthebarcompleteswecleartheinterval:

constProgressBar=require('progress')

constbar=newProgressBar(':bar',{total:10})

consttimer=setInterval(()=>{

bar.tick()

if(bar.complete){

clearInterval(timer)

}

},100)

Outputtothecommandline

39

Page 40: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Outputtothecommandline

40

Page 41: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

AcceptinputfromthecommandlineHowtomakeaNode.jsCLIprograminteractiveusingthebuilt-inreadlineNodemodule

HowtomakeaNode.jsCLIprograminteractive?

Nodesinceversion7providesthe readlinemoduletoperformexactlythis:getinputfromareadablestreamsuchasthe process.stdinstream,whichduringtheexecutionofaNodeprogramistheterminalinput,onelineatatime.

constreadline=require('readline').createInterface({

input:process.stdin,

output:process.stdout

})

readline.question(`What'syourname?`,(name)=>{

console.log(`Hi${name}!`)

readline.close()

})

Thispieceofcodeaskstheusername,andoncethetextisenteredandtheuserpressesenter,wesendagreeting.

The question()methodshowsthefirstparameter(aquestion)andwaitsfortheuserinput.Itcallsthecallbackfunctiononceenterispressed.

Inthiscallbackfunction,weclosethereadlineinterface.

readlineoffersseveralothermethods,andI'llletyoucheckthemoutonthepackagedocumentationIlinkedabove.

Ifyouneedtorequireapassword,it'sbesttonowechoitback,butinsteadshowinga *symbol.

Thesimplestwayistousethe readline-syncpackagewhichisverysimilarintermsoftheAPIandhandlesthisoutofthebox.

AmorecompleteandabstractsolutionisprovidedbytheInquirer.jspackage.

Youcaninstallitusing npminstallinquirer,andthenyoucanreplicatetheabovecodelikethis:

constinquirer=require('inquirer')

varquestions=[{

type:'input',

Acceptinputfromthecommandline

41

Page 42: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

name:'name',

message:"What'syourname?",

}]

inquirer.prompt(questions).then(answers=>{

console.log(`Hi${answers['name']}!`)

})

Inquirer.jsletsyoudomanythingslikeaskingmultiplechoices,havingradiobuttons,confirmations,andmore.

It'sworthknowingallthealternatives,especiallythebuilt-inonesprovidedbyNode,butifyouplantotakeCLIinputtothenextlevel,Inquirer.jsisanoptimalchoice.

Acceptinputfromthecommandline

42

Page 43: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ExposefunctionalityfromaNodefileusingexportsHowtousethemodule.exportsAPItoexposedatatootherfilesinyourapplication,ortootherapplicationsaswell

Nodehasabuilt-inmodulesystem.

ANode.jsfilecanimportfunctionalityexposedbyotherNode.jsfiles.

Whenyouwanttoimportsomethingyouuse

constlibrary=require('./library')

toimportthefunctionalityexposedinthe library.jsfilethatresidesinthecurrentfilefolder.

Inthisfile,functionalitymustbeexposedbeforeitcanbeimportedbyotherfiles.

Anyotherobjectorvariabledefinedinthefilebydefaultisprivateandnotexposedtotheouterworld.

Thisiswhatthe module.exportsAPIofferedbythe modulesystemallowsustodo.

Whenyouassignanobjectorafunctionasanew exportsproperty,thatisthethingthat'sbeingexposed,andassuch,itcanbeimportedinotherpartsofyourapp,orinotherappsaswell.

Youcandosoin2ways.

Thefirstistoassignanobjectto module.exports,whichisanobjectprovidedoutoftheboxbythemodulesystem,andthiswillmakeyourfileexportjustthatobject:

constcar={

brand:'Ford',

model:'Fiesta'

}

module.exports=car

//..intheotherfile

constcar=require('./car')

Thesecondwayistoaddtheexportedobjectasapropertyof exports.Thiswayallowsyoutoexportmultipleobjects,functionsordata:

ExposefunctionalityfromaNodefileusingexports

43

Page 44: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

constcar={

brand:'Ford',

model:'Fiesta'

}

exports.car=car

ordirectly

exports.car={

brand:'Ford',

model:'Fiesta'

}

Andintheotherfile,you'lluseitbyreferencingapropertyofyourimport:

constitems=require('./items')

items.car

or

constcar=require('./items').car

What'sthedifferencebetween module.exportsand exports?

Thefirstexposestheobjectitpointsto.Thelatterexposesthepropertiesoftheobjectitpointsto.

ExposefunctionalityfromaNodefileusingexports

44

Page 45: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

npmAquickguidetonpm,thepowerfulpackagemanagerkeytothesuccessofNode.js.InJanuary2017over350000packageswerereportedbeinglistedinthenpmregistry,makingitthebiggestsinglelanguagecoderepositoryonEarth,andyoucanbesurethereisapackagefor(almost!)everything.

IntroductiontonpmDownloads

InstallingalldependenciesInstallingasinglepackageUpdatingpackages

VersioningRunningTasks

IntroductiontonpmnpmisthestandardpackagemanagerforNode.js.

npm

45

Page 46: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

InJanuary2017over350000packageswerereportedbeinglistedinthenpmregistry,makingitthebiggestsinglelanguagecoderepositoryonEarth,andyoucanbesurethereisapackagefor(almost!)everything.

ItstartedasawaytodownloadandmanagedependenciesofNode.jspackages,butithassincebecomeatoolusedalsoinfrontendJavaScript.

Therearemanythingsthat npmdoes.

Yarnisanalternativetonpm.Makesureyoucheckitoutaswell.

Downloadsnpmmanagesdownloadsofdependenciesofyourproject.

Installingalldependencies

Ifaprojecthasa packages.jsonfile,byrunning

npminstall

itwillinstalleverythingtheprojectneeds,inthe node_modulesfolder,creatingitifit'snotexistingalready.

Installingasinglepackage

Youcanalsoinstallaspecificpackagebyrunning

npminstall<package-name>

Oftenyou'llseemoreflagsaddedtothiscommand:

--saveinstallsandaddstheentrytothe package.jsonfiledependencies--save-devinstallsandaddstheentrytothe package.jsonfiledevDependencies

ThedifferenceismainlythatdevDependenciesareusuallydevelopmenttools,likeatestinglibrary,while dependenciesarebundledwiththeappinproduction.

Updatingpackages

Updatingisalsomadeeasy,byrunning

npmupdate

npm

46

Page 47: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

npmwillcheckallpackagesforanewerversionthatsatisfiesyourversioningconstraints.

Youcanspecifyasinglepackagetoupdateaswell:

npmupdate<package-name>

VersioningInadditiontoplaindownloads, npmalsomanagesversioning,soyoucanspecifyanyspecificversionofapackage,orrequireaversionhigherorlowerthanwhatyouneed.

Manytimesyou'llfindthatalibraryisonlycompatiblewithamajorreleaseofanotherlibrary.

Orabuginthelatestreleaseofalib,stillunfixed,iscausinganissue.

Specifyinganexplicitversionofalibraryalsohelpstokeepeveryoneonthesameexactversionofapackage,sothatthewholeteamrunsthesameversionuntilthe package.jsonfileisupdated.

Inallthosecases,versioninghelpsalot,and npmfollowsthesemanticversioning(semver)standard.

RunningTasksThepackage.jsonfilesupportsaformatforspecifyingcommandlinetasksthatcanberunbyusing

npmrun<task-name>

Forexample:

{

"scripts":{

"start-dev":"nodelib/server-development",

"start":"nodelib/server-production"

},

}

It'sverycommontousethisfeaturetorunWebpack:

{

"scripts":{

npm

47

Page 48: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"watch":"webpack--watch--progress--colors--configwebpack.conf.js",

"dev":"webpack--progress--colors--configwebpack.conf.js",

"prod":"NODE_ENV=productionwebpack-p--configwebpack.conf.js",

},

}

Soinsteadoftypingthoselongcommands,whichareeasytoforgetormistype,youcanrun

$npmrunwatch

$npmrundev

$npmrunprod

npm

48

Page 49: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WheredoesnpminstallthepackagesHowtofindoutwherenpminstallsthepackages

Readthenpmguideifyouarestartingoutwithnpm,it'sgoingtogoinalotofthebasicdetailsofit.

Whenyouinstallapackageusing npm(oryarn),youcanperform2typesofinstallation:

alocalinstallaglobalinstall

Bydefault,whenyoutypean npminstallcommand,like:

npminstalllodash

thepackageisinstalledinthecurrentfiletree,underthe node_modulessubfolder.

Asthishappens, npmalsoaddsthe lodashentryinthe dependenciespropertyofthepackage.jsonfilepresentinthecurrentfolder.

Aglobalinstallationisperformedusingthe -gflag:

npminstall-glodash

Whenthishappens,npmwon'tinstallthepackageunderthelocalfolder,butinstead,itwilluseagloballocation.

Where,exactly?

The npmroot-gcommandwilltellyouwherethatexactlocationisonyourmachine.

OnmacOSorLinuxthislocationcouldbe /usr/local/lib/node_modules.OnWindowsitcouldbe C:\Users\YOU\AppData\Roaming\npm\node_modules

Ifyouuse nvmtomanageNode.jsversions,however,thatlocationwoulddiffer.

Iforexampleuse nvmandmypackageslocationwasshownas/Users/flavio/.nvm/versions/node/v8.9.0/lib/node_modules.

Wheredoesnpminstallthepackages

49

Page 50: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtouseorexecuteapackageinstalledusingnpmHowtoincludeanduseinyourcodeapackageinstalledinyournode_modulesfolder

Whenyouinstallusing npmapackageintoyour node_modulesfolder,oralsoglobally,howdoyouuseitinyourNodecode?

Sayyouinstall lodash,thepopularJavaScriptutilitylibrary,using

npminstalllodash

Thisisgoingtoinstallthepackageinthelocal node_modulesfolder.

Touseitinyourcode,youjustneedtoimportitintoyourprogramusing require:

const_=require('lodash)

Whatifyourpackageisanexecutable?

Inthiscase,itwillputtheexecutablefileunderthe node_modules/.bin/folder.

Oneeasywaytodemonstratethisiscowsay.

Thecowsaypackageprovidesacommandlineprogramthatcanbeexecutedtomakeacowsaysomething(andotheranimalsaswellࢤ ).

Whenyouinstallthepackageusing npminstallcowsay,itwillinstallitselfandafewdependenciesinthenode_modulesfolder:

Howtouseorexecuteapackageinstalledusingnpm

50

Page 51: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thereisahidden.binfolder,whichcontainssymboliclinkstothecowsaybinaries:

Howdoyouexecutethose?

Youcanofcoursetype ./node_modules/.bin/cowsaytorunit,anditworks,butnpx,includedintherecentversionsofnpm(since5.2),isamuchbetteroption.Youjustrun:

npxcowsay

andnpxwillfindthepackagelocation.

Howtouseorexecuteapackageinstalledusingnpm

51

Page 52: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Howtouseorexecuteapackageinstalledusingnpm

52

Page 53: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thepackage.jsonfileThepackage.jsonfileisakeyelementinlotsofappcodebasesbasedontheNode.jsecosystem.

IfyouworkwithJavaScript,oryou'veeverinteractedwithaJavaScriptproject,Node.jsorafrontendproject,yousurelymetthe package.jsonfile.

What'sthatfor?Whatshouldyouknowaboutit,andwhataresomeofthecoolthingsyoucandowithit?

The package.jsonfileiskindofamanifestforyourproject.Itcandoalotofthings,completelyunrelated.It'sacentralrepositoryofconfigurationfortools,forexample.It'salsowhere npmand yarnstorethenamesandversionsofthepackageitinstalled.

ThefilestructurePropertiesbreakdown

name

author

contributors

bugs

homepage

version

license

keywords

description

repository

main

private

scripts

dependencies

devDependencies

engines

browserslist

Command-specificpropertiesPackageversions

ThefilestructureHere'sanexamplepackage.jsonfile:

Thepackage.jsonfile

53

Page 54: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

{

}

It'sempty!Therearenofixedrequirementsofwhatshouldbeina package.jsonfile,foranapplication.TheonlyrequirementisthatitrespectstheJSONformat,otherwiseitcannotbereadbyprogramsthattrytoaccessitspropertiesprogrammatically.

Ifyou'rebuildingaNode.jspackagethatyouwanttodistributeover npmthingschangeradically,andyoumusthaveasetofpropertiesthatwillhelpotherpeopleuseit.We'llseemoreaboutthislateron.

Thisisanotherpackage.json:

{

"name":"test-project"

}

Itdefinesa nameproperty,whichtellsthenameoftheapp,orpackage,that'scontainedinthesamefolderwherethisfilelives.

Here'samuchmorecomplexexample,whichIextractedthisfromasampleVue.jsapplication:

{

"name":"test-project",

"version":"1.0.0",

"description":"AVue.jsproject",

"main":"src/main.js",

"private":true,

"scripts":{

"dev":"webpack-dev-server--inline--progress--configbuild/webpack.dev.conf.js",

"start":"npmrundev",

"unit":"jest--configtest/unit/jest.conf.js--coverage",

"test":"npmrununit",

"lint":"eslint--ext.js,.vuesrctest/unit",

"build":"nodebuild/build.js"

},

"dependencies":{

"vue":"^2.5.2"

},

"devDependencies":{

"autoprefixer":"^7.1.2",

"babel-core":"^6.22.1",

"babel-eslint":"^8.2.1",

"babel-helper-vue-jsx-merge-props":"^2.0.3",

"babel-jest":"^21.0.2",

"babel-loader":"^7.1.1",

"babel-plugin-dynamic-import-node":"^1.2.0",

"babel-plugin-syntax-jsx":"^6.18.0",

Thepackage.jsonfile

54

Page 55: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"babel-plugin-transform-es2015-modules-commonjs":"^6.26.0",

"babel-plugin-transform-runtime":"^6.22.0",

"babel-plugin-transform-vue-jsx":"^3.5.0",

"babel-preset-env":"^1.3.2",

"babel-preset-stage-2":"^6.22.0",

"chalk":"^2.0.1",

"copy-webpack-plugin":"^4.0.1",

"css-loader":"^0.28.0",

"eslint":"^4.15.0",

"eslint-config-airbnb-base":"^11.3.0",

"eslint-friendly-formatter":"^3.0.0",

"eslint-import-resolver-webpack":"^0.8.3",

"eslint-loader":"^1.7.1",

"eslint-plugin-import":"^2.7.0",

"eslint-plugin-vue":"^4.0.0",

"extract-text-webpack-plugin":"^3.0.0",

"file-loader":"^1.1.4",

"friendly-errors-webpack-plugin":"^1.6.1",

"html-webpack-plugin":"^2.30.1",

"jest":"^22.0.4",

"jest-serializer-vue":"^0.3.0",

"node-notifier":"^5.1.2",

"optimize-css-assets-webpack-plugin":"^3.2.0",

"ora":"^1.2.0",

"portfinder":"^1.0.13",

"postcss-import":"^11.0.0",

"postcss-loader":"^2.0.8",

"postcss-url":"^7.2.1",

"rimraf":"^2.6.0",

"semver":"^5.3.0",

"shelljs":"^0.7.6",

"uglifyjs-webpack-plugin":"^1.1.1",

"url-loader":"^0.5.8",

"vue-jest":"^1.0.2",

"vue-loader":"^13.3.0",

"vue-style-loader":"^3.0.1",

"vue-template-compiler":"^2.5.2",

"webpack":"^3.6.0",

"webpack-bundle-analyzer":"^2.9.0",

"webpack-dev-server":"^2.9.1",

"webpack-merge":"^4.1.0"

},

"engines":{

"node":">=6.0.0",

"npm":">=3.0.0"

},

"browserslist":[

">1%",

"last2versions",

"notie<=8"

]

}

therearelotsofthingsgoingonhere:

Thepackage.jsonfile

55

Page 56: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

namesetstheapplication/packagenameversionindicatesthecurrentversiondescriptionisabriefdescriptionoftheapp/packagemainsettheentrypointfortheapplicationprivateifsetto truepreventstheapp/packagetobeaccidentallypublishedon npmscriptsdefinesasetofnodescriptsyoucanrundependenciessetsalistof npmpackagesinstalledasdependenciesdevDependenciessetsalistof npmpackagesinstalledasdevelopmentdependenciesenginessetswhichversionsofNodethispackage/appworksonbrowserslistisusedtotellwhichbrowsers(andtheirversions)youwanttosupport

Allthosepropertiesareusedbyeither npmorothertoolsthatwecanuse.

PropertiesbreakdownThissectiondescribesthepropertiesyoucanuseindetail.Ireferto"package"butthesamethingappliestolocalapplicationswhichyoudonotuseaspackages.

Mostofthosepropertiesareonlyusedonthehttps://www.npmjs.com/,otherbyscriptsthatinteractwithyourcode,like npmorothers.

name

Setsthepackagename.

Example:

"name":"test-project"

Thenamemustbelessthan214characters,mustnothavespaces,itcanonlycontainlowercaseletters,hyphens( -)orunderscores( _).

Thisisbecausewhenapackageispublishedon npm,itgetsitsownURLbasedonthisproperty.

IfyoupublishedthispackagepubliclyonGitHub,agoodvalueforthispropertyistheGitHubrepositoryname.

author

Liststhepackageauthorname

Example:

Thepackage.jsonfile

56

Page 57: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

{

"author":"FlavioCopes<[email protected]>(https://flaviocopes.com)"

}

Canalsobeusedwiththisformat:

{

"author":{

"name":"FlavioCopes",

"email":"[email protected]",

"url":"https://flaviocopes.com"

}

}

contributors

Aswellastheauthor,theprojectcanhaveoneormorecontributors.Thispropertyisanarraythatliststhem.

Example:

{

"contributors":[

"FlavioCopes<[email protected]>(https://flaviocopes.com)"

]

}

Canalsobeusedwiththisformat:

{

"contributors":[

{

"name":"FlavioCopes",

"email":"[email protected]",

"url":"https://flaviocopes.com"

}

]

}

bugs

Linkstothepackageissuetracker,mostlikelyaGitHubissuespage

Example:

{

"bugs":"https://github.com/flaviocopes/package/issues"

Thepackage.jsonfile

57

Page 58: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

}

homepage

Setsthepackagehomepage

Example:

{

"homepage":"https://flaviocopes.com/package"

}

version

Indicatesthecurrentversionofthepackage.

Example:

"version":"1.0.0"

Thispropertyfollowsthesemanticversioning(semver)notationforversions,whichmeanstheversionisalwaysexpressedwith3numbers: x.x.x.

Thefirstnumberisthemajorversion,thesecondtheminorversionandthethirdisthepatchversion.

Thereisameaninginthesenumbers:areleasethatonlyfixesbugsisapatchrelease,areleasethatintroducesbackward-compatiblechangesisaminorrelease,amajorreleasecanhavebreakingchanges.

license

Indicatesthelicenseofthepackage.

Example:

"license":"MIT"

keywords

Thispropertycontainsanarrayofkeywordsthatassociatewithwhatyourpackagedoes.

Example:

Thepackage.jsonfile

58

Page 59: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"keywords":[

"email",

"machinelearning",

"ai"

]

Thishelpspeoplefindyourpackagewhennavigatingsimilarpackages,orwhenbrowsingthehttps://www.npmjs.com/website.

description

Thispropertycontainsabriefdescriptionofthepackage

Example:

"description":"Apackagetoworkwithstrings"

Thisisespeciallyusefulifyoudecidetopublishyourpackageto npmsothatpeoplecanfindoutwhatthepackageisabout.

repository

Thispropertyspecifieswherethispackagerepositoryislocated.

Example:

"repository":"github:flaviocopes/testing",

Noticethe githubprefix.Thereareotherpopularservicesbakedin:

"repository":"gitlab:flaviocopes/testing",

"repository":"bitbucket:flaviocopes/testing",

Youcanexplicitlysettheversioncontrolsystem:

"repository":{

"type":"git",

"url":"https://github.com/flaviocopes/testing.git"

}

Youcanusedifferentversioncontrolsystems:

Thepackage.jsonfile

59

Page 60: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"repository":{

"type":"svn",

"url":"..."

}

main

Setstheentrypointforthepackage.

Whenyouimportthispackageinanapplication,that'swheretheapplicationwillsearchforthemoduleexports.

Example:

"main":"src/main.js"

private

ifsetto truepreventstheapp/packagetobeaccidentallypublishedon npm

Example:

"private":true

scripts

Definesasetofnodescriptsyoucanrun

Example:

"scripts":{

"dev":"webpack-dev-server--inline--progress--configbuild/webpack.dev.conf.js",

"start":"npmrundev",

"unit":"jest--configtest/unit/jest.conf.js--coverage",

"test":"npmrununit",

"lint":"eslint--ext.js,.vuesrctest/unit",

"build":"nodebuild/build.js"

}

Thesescriptsarecommandlineapplications.Youcanrunthembycalling npmrunXXXXoryarnXXXX,where XXXXisthecommandname.Example: npmrundev.

Youcanuseanynameyouwantforacommand,andscriptscandoliterallyanythingyouwant.

Thepackage.jsonfile

60

Page 61: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

dependencies

Setsalistof npmpackagesinstalledasdependencies.

Whenyouinstallapackageusingnpmoryarn:

npminstall<PACKAGENAME>

yarnadd<PACKAGENAME>

thatpackageisautomaticallyinsertedinthislist.

Example:

"dependencies":{

"vue":"^2.5.2"

}

devDependencies

Setsalistof npmpackagesinstalledasdevelopmentdependencies.

Theydifferfrom dependenciesbecausetheyaremeanttobeinstalledonlyonadevelopmentmachine,notneededtorunthecodeinproduction.

Whenyouinstallapackageusingnpmoryarn:

npminstall--dev<PACKAGENAME>

yarnadd--dev<PACKAGENAME>

thatpackageisautomaticallyinsertedinthislist.

Example:

"devDependencies":{

"autoprefixer":"^7.1.2",

"babel-core":"^6.22.1"

}

engines

SetswhichversionsofNode.jsandothercommandsthispackage/appworkon

Example:

"engines":{

Thepackage.jsonfile

61

Page 62: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"node":">=6.0.0",

"npm":">=3.0.0",

"yarn":"^0.13.0"

}

browserslist

Isusedtotellwhichbrowsers(andtheirversions)youwanttosupport.It'sreferencedbyBabel,Autoprefixer,andothertools,toonlyaddthepolyfillsandfallbacksneededtothebrowsersyoutarget.

Example:

"browserslist":[

">1%",

"last2versions",

"notie<=8"

]

Thisconfigurationmeansyouwanttosupportthelast2majorversionsofallbrowserswithatleast1%ofusage(fromtheCanIUse.comstats),exceptIE8andlower.

(seemore)

Command-specificproperties

The package.jsonfilecanalsohostcommand-specificconfiguration,forexampleforBabel,ESLint,andmore.

Eachhasaspecificproperty,like eslintConfig, babelandothers.Thosearecommand-specific,andyoucanfindhowtousethoseintherespectivecommand/projectdocumentation.

PackageversionsYouhaveseeninthedescriptionaboveversionnumberslikethese: ~3.0.0or 0.13.0.Whatdotheymean,andwhichotherversionspecifierscanyouuse?

Thatsymbolspecifieswhichupdatesyoupackageaccepts,fromthatdependency.

Giventhatusingsemver(semanticversioning)allversionshave3digits,thefirstbeingthemajorrelease,thesecondtheminorreleaseandthethirdisthepatchrelease,youhavetheserules:

~:ifyouwrite ~0.13.0,youwanttoonlyupdatepatchreleases: 0.13.1isok,but

Thepackage.jsonfile

62

Page 63: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

0.14.0isnot. :ifyouwrite 0.13.0,youwanttoupdatepatchandminorreleases: 0.13.1, 0.14.0andsoon.*:ifyouwrite *,thatmeansyouacceptallupdates,includingmajorversionupgrades.>:youacceptanyversionhigherthantheoneyouspecify>=:youacceptanyversionequaltoorhigherthantheoneyouspecify<=:youacceptanyversionequalorlowertotheoneyouspecify<:youacceptanyversionlowertotheoneyouspecify

Thereareotherrules,too:

nosymbol:youacceptonlythatspecificversionyouspecifylatest:youwanttousethelatestversionavailable

andyoucancombinemostoftheaboveinranges,likethis: 1.0.0||>=1.1.0<1.2.0,toeitheruse1.0.0oronereleasefrom1.1.0up,butlowerthan1.2.0.

Thepackage.jsonfile

63

Page 64: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thepackage-lock.jsonfileThepackage-lock.jsonfileisautomaticallygeneratedwheninstallingnodepackages.Learnwhatit'sabout

Inversion5,npmintroducedthe package-lock.jsonfile.

What'sthat?Youprobablyknowaboutthe package.jsonfile,whichismuchmorecommonandhasbeenaroundformuchlonger.

Thegoalofthefileistokeeptrackoftheexactversionofeverypackagethatisinstalledsothataproductis100%reproducibleinthesamewayevenifpackagesareupdatedbytheirmaintainers.

Thissolvesaveryspecificproblemthat package.jsonleftunsolved.Inpackage.jsonyoucansetwhichversionsyouwanttoupgradeto(patchorminor),usingthesemvernotation,forexample:

ifyouwrite ~0.13.0,youwanttoonlyupdatepatchreleases: 0.13.1isok,but 0.14.0isnot.ifyouwrite 0.13.0,youwanttoupdatepatchandminorreleases: 0.13.1, 0.14.0andsoon.ifyouwrite 0.13.0,thatistheexactversionthatwillbeused,always

Youdon'tcommittoGityournode_modulesfolder,whichisgenerallyhuge,andwhenyoutrytoreplicatetheprojectonanothermachinebyusingthe npminstallcommand,ifyouspecifiedthe ~syntaxandapatchreleaseofapackagehasbeenreleased,thatoneisgoingtobeinstalled.Samefor andminorreleases.

Ifyouspecifyexactversions,like 0.13.0intheexample,youarenotaffectedbythisproblem.

Itcouldbeyou,oranotherpersontryingtoinitializetheprojectontheothersideoftheworldbyrunning npminstall.

Soyouroriginalprojectandthenewlyinitializedprojectareactuallydifferent.Evenifapatchorminorreleaseshouldnotintroducebreakingchanges,weallknowbugscan(andso,theywill)slidein.

The package-lock.jsonsetsyourcurrentlyinstalledversionofeachpackageinstone,andnpmwillusethoseexactversionswhenrunning npminstall.

Thisconceptisnotnew,andotherprogramminglanguagespackagemanagers(likeComposerinPHP)useasimilarsystemforyears.

Thepackage-lock.jsonfile

64

Page 65: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

The package-lock.jsonfileneedstobecommittedtoyourGitrepository,soitcanbefetchedbyotherpeople,iftheprojectispublicoryouhavecollaborators,orifyouuseGitasasourcefordeployments.

Thedependenciesversionswillbeupdatedinthe package-lock.jsonfilewhenyourun npmupdate.

AnexampleThisisanexamplestructureofa package-lock.jsonfilewegetwhenwerun npminstallcowsayinanemptyfolder:

{

"requires":true,

"lockfileVersion":1,

"dependencies":{

"ansi-regex":{

"version":"3.0.0",

"resolved":"https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.

0.0.tgz",

"integrity":"sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="

},

"cowsay":{

"version":"1.3.1",

"resolved":"https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz"

,

"integrity":"sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkM

Ajufp+0F9eLjzRnOHzVAYeIYFF5po5NjRrgefnRMQ==",

"requires":{

"get-stdin":"^5.0.1",

"optimist":"~0.6.1",

"string-width":"~2.1.1",

"strip-eof":"^1.0.0"

}

},

"get-stdin":{

"version":"5.0.1",

"resolved":"https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.

1.tgz",

"integrity":"sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g="

},

"is-fullwidth-code-point":{

"version":"2.0.0",

"resolved":"https://registry.npmjs.org/is-fullwidth-code-point/-/

is-fullwidth-code-point-2.0.0.tgz",

"integrity":"sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="

},

"minimist":{

"version":"0.0.10",

"resolved":"https://registry.npmjs.org/minimist/-/minimist-0.0.10

.tgz",

Thepackage-lock.jsonfile

65

Page 66: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

"integrity":"sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="

},

"optimist":{

"version":"0.6.1",

"resolved":"https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",

"integrity":"sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",

"requires":{

"minimist":"~0.0.1",

"wordwrap":"~0.0.2"

}

},

"string-width":{

"version":"2.1.1",

"resolved":"https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",

"integrity":"sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaT

jAqvVwdfeZ7w7aCvJD7ugkw==",

"requires":{

"is-fullwidth-code-point":"^2.0.0",

"strip-ansi":"^4.0.0"

}

},

"strip-ansi":{

"version":"4.0.0",

"resolved":"https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",

"integrity":"sha1-qEeQIusaw2iocTibY1JixQXuNo8=",

"requires":{

"ansi-regex":"^3.0.0"

}

},

"strip-eof":{

"version":"1.0.0",

"resolved":"https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",

"integrity":"sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="

},

"wordwrap":{

"version":"0.0.3",

"resolved":"https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",

"integrity":"sha1-o9XabNXAvAAI03I0u68b7WMFkQc="

}

}

}

Weinstalled cowsay,whichdependson

get-stdin

optimist

string-width

strip-eof

Inturn,thosepackagesrequireotherpackages,aswecanseefromthe requirespropertythatsomehave:

Thepackage-lock.jsonfile

66

Page 67: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ansi-regex

is-fullwidth-code-point

minimist

wordwrap

strip-eof

Theyareaddedinalphabeticalorderintothefile,andeachonehasa versionfield,aresolvedfieldthatpointstothepackagelocation,andan integritystringthatwecanusetoverifythepackage.

Thepackage-lock.jsonfile

67

Page 68: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

FindtheinstalledversionofannpmpackageHowtofindoutwhichversionofaparticularpackageyouhaveinstalledinyourapp

Toseethelatestversionofallthenpmpackageinstalled,includingtheirdependencies:

npmlist

Example:

❯npmlist/Users/flavio/dev/node/cowsay

└─┬[email protected]

├──[email protected]

├─┬[email protected]

│├──[email protected]

│└──[email protected]

├─┬[email protected]

│├──[email protected]

│└─┬[email protected]

│└──[email protected]

└──[email protected]

Youcanalsojustopenthe package-lock.jsonfile,butthisinvolvessomevisualscanning.

npmlist-gisthesame,butforgloballyinstalledpackages.

Togetonlyyourtop-levelpackages(basically,theonesyoutoldnpmtoinstallandyoulistedinthe package.json),run npmlist--depth=0:

❯npmlist--depth=0/Users/flavio/dev/node/cowsay

└──[email protected]

Youcangettheversionofaspecificpackagebyspecifyingthename:

❯npmlistcowsay/Users/flavio/dev/node/cowsay

└──[email protected]

Thisalsoworksfordependenciesofpackagesyouinstalled:

Findtheinstalledversionofannpmpackage

68

Page 69: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

❯npmlistminimist/Users/flavio/dev/node/cowsay

└─┬[email protected]

└─┬[email protected]

└──[email protected]

Ifyouwanttoseewhat'sthelatestavailableversionofthepackageonthenpmrepository,runnpmview[package_name]version:

❯npmviewcowsayversion

1.3.1

Findtheinstalledversionofannpmpackage

69

Page 70: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtoinstallanolderversionofannpmpackageLearnhowtoinstallanolderversionofannpmpackage,somethingthatmightbeusefultosolveacompatibilityproblem

Youcaninstallanoldversionofannpmpackageusingthe @syntax:

npminstall<package>@<version>

Example:

npminstallcowsay

installsversion1.3.1(atthetimeofwriting).

Installversion1.2.0with:

[email protected]

Thesamecanbedonewithglobalpackages:

[email protected]

Youmightalsobeinterestedinlistingallthepreviousversionofapackage.Youcandoitwithnpmview<package>versions:

❯npmviewcowsayversions

['1.0.0',

'1.0.1',

'1.0.2',

'1.0.3',

'1.1.0',

'1.1.1',

'1.1.2',

'1.1.3',

'1.1.4',

'1.1.5',

'1.1.6',

'1.1.7',

'1.1.8',

'1.1.9',

'1.2.0',

'1.2.1',

Howtoinstallanolderversionofannpmpackage

70

Page 71: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

'1.3.0',

'1.3.1']

Howtoinstallanolderversionofannpmpackage

71

Page 72: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowtoupdatealltheNodedependenciestotheirlatestversionHowdoyouupdateallthenpmdependenciesstoreinthepackage.jsonfile,totheirlatestversionavailable?

Whenyouinstallapackageusing npminstall<packagename>,thelatestavailableversionofthepackageisdownloadedandputinthe node_modulesfolder,andacorrespondingentryisaddedtothe package.jsonand package-lock.jsonfilesthatarepresentinyourcurrentfolder.

npmcalculatesthedependenciesandinstallsthelatestavailableversionofthoseaswell.

Let'ssayyouinstall cowsay,acoolcommandlinetoolthatletsyoumakeacowsaythings.

Whenyou npminstallcowsay,thisentryisaddedtothe package.jsonfile:

{

"dependencies":{

"cowsay":"^1.3.1"

}

}

andthisisanextractof package-lock.json,whereIremovedthenesteddependenciesforclarity:

{

"requires":true,

"lockfileVersion":1,

"dependencies":{

"cowsay":{

"version":"1.3.1",

"resolved":"https://registry.npmjs.org/cowsay/-/cowsay-1.3.1.tgz",

"integrity":"sha512-3PVFe6FePVtPj1HTeLin9v8WyLl+VmM1l1H/5P+BTTDkMAjufp+0F9eLjzRnOHz

VAYeIYFF5po5NjRrgefnRMQ==",

"requires":{

"get-stdin":"^5.0.1",

"optimist":"~0.6.1",

"string-width":"~2.1.1",

"strip-eof":"^1.0.0"

}

}

}

}

HowtoupdatealltheNodedependenciestotheirlatestversion

72

Page 73: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Nowthose2filestellusthatweinstalledversion 1.3.1ofcowsay,andourruleforupdatesis 1.3.1,whichforthenpmversioningrulesmeansthatnpmcanupdatetopatchandminorreleases: 0.13.1, 0.14.0andsoon.

Ifthereisanewminororpatchreleaseandwetype npmupdate,theinstalledversionisupdated,andthe package-lock.jsonfilediligentlyfilledwiththenewversion.

package.jsonremainsunchanged.

Todiscovernewreleasesofthepackages,yourun npmoutdated.

Here'sthelistofafewoutdatedpackagesinonerepositoryIdidn'tupdateforquiteawhile:

Someofthoseupdatesaremajorreleases.Running npmupdatewon'tupdatetheversionofthose.Majorreleasesareneverupdatedinthiswaybecausethey(bydefinition)introducebreakingchanges,and npmwanttosaveyoutrouble.

Toupdatetoanewmajorversionallthepackages,installthe npm-check-updatespackageglobally:

npminstall-gnpm-check-updates

thenrunit:

ncu-u

HowtoupdatealltheNodedependenciestotheirlatestversion

73

Page 74: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

thiswillupgradealltheversionhintsinthe package.jsonfile,to dependenciesanddevDependencies,sonpmcaninstallthenewmajorversion.

Youarenowreadytoruntheupdate:

npmupdate

Ifyoujustdownloadedtheprojectwithoutthe node_modulesdependenciesandyouwanttoinstalltheshinynewversionsfirst,justrun

npminstall

HowtoupdatealltheNodedependenciestotheirlatestversion

74

Page 75: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

SemanticversioningrulesSemanticVersioningisaconventionusedtoprovideameaningtoversions

Ifthere'sonegreatthinginNode.jspackages,isthatallagreedonusingSemanticVersioningfortheirversionnumbering.

TheSemanticVersioningconceptissimple:allversionshave3digits: x.y.z.

thefirstdigitisthemajorversiontheseconddigitistheminorversionthethirddigitisthepatchversion

Whenyoumakeanewrelease,youdon'tjustupanumberasyouplease,butyouhaverules:

youupthemajorversionwhenyoumakeincompatibleAPIchangesyouuptheminorversionwhenyouaddfunctionalityinabackward-compatiblemanneryouupthepatchversionwhenyoumakebackward-compatiblebugfixes

Theconventionisadoptedallacrossprogramminglanguages,anditisveryimportantthatevery npmpackageadherestoit,becausethewholesystemdependsonthat.

Whyisthatsoimportant?

Because npmsetsomeruleswecanuseinthe package.jsonfiletochoosewhichversionsitcanupdateourpackagesto,whenwerun npmupdate.

Therulesusethosesymbols:

~

>

>=

<

<=

=

-

||

Let'sseethoserulesindetail:

:ifyouwrite 0.13.0whenrunning npmupdateitcanupdatetopatchandminorreleases: 0.13.1, 0.14.0andsoon.~:ifyouwrite ~0.13.0,whenrunning npmupdateitcanupdatetopatchreleases:0.13.1isok,but 0.14.0isnot.

Semanticversioningrules

75

Page 76: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

>:youacceptanyversionhigherthantheoneyouspecify>=:youacceptanyversionequaltoorhigherthantheoneyouspecify<=:youacceptanyversionequalorlowertotheoneyouspecify<:youacceptanyversionlowertotheoneyouspecify=:youacceptthatexactversion-:youacceptarangeofversions.Example: 2.1.0-2.6.2||:youcombinesets.Example: <2.1||>2.6

Youcancombinesomeofthosenotations,forexampleuse 1.0.0||>=1.1.0<1.2.0toeitheruse1.0.0oronereleasefrom1.1.0up,butlowerthan1.2.0.

Thereareotherrules,too:

nosymbol:youacceptonlythatspecificversionyouspecify( 1.2.1)latest:youwanttousethelatestversionavailable

Semanticversioningrules

76

Page 77: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

UninstallingnpmpackagesHowtouninstallannpmNodepackage,locallyorglobally

Touninstallapackageyouhavepreviouslyinstalledlocally(using npminstall<package-name>inthe node_modulesfolder,run

npmuninstall<package-name>

fromtheprojectrootfolder(thefolderthatcontainsthenode_modulesfolder).

Usingthe -Sflag,or --save,thisoperationwillalsoremovethereferenceinthepackage.jsonfile.

Ifthepackagewasadevelopmentdependency,listedinthedevDependenciesofthepackage.jsonfile,youmustusethe -D/ --save-devflagtoremoveitfromthefile:

npmuninstall-S<package-name>

npmuninstall-D<package-name>

Ifthepackageisinstalledglobally,youneedtoaddthe -g/ --globalflag:

npmuninstall-g<package-name>

forexample:

npmuninstall-gwebpack

andyoucanrunthiscommandfromanywhereyouwantonyoursystembecausethefolderwhereyoucurrentlyaredoesnotmatter.

Uninstallingnpmpackages

77

Page 78: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

GlobalorlocalpackagesWhenisapackagebestinstalledglobally?Why?

Themaindifferencebetweenlocalandglobalpackagesisthis:

localpackagesareinstalledinthedirectorywhereyourun npminstall<package-name>,andtheyareputinthe node_modulesfolderunderthisdirectoryglobalpackagesareallputinasingleplaceinyoursystem(exactlywheredependsonyoursetup),regardlessofwhereyourun npminstall-g<package-name>

Inyourcode,theyarebothrequiredinthesameway:

require('package-name')

sowhenshouldyouinstallinonewayoranother?

Ingeneral,allpackagesshouldbeinstalledlocally.

Thismakessureyoucanhavedozensofapplicationsinyourcomputer,allrunningadifferentversionofeachpackageifneeded.

Updatingaglobalpackagewouldmakeallyourprojectsusethenewrelease,andasyoucanimaginethismightcausenightmaresintermsofmaintenance,assomepackagesmightbreakcompatibilitywithfurtherdependencies,andsoon.

Allprojectshavetheirownlocalversionofapackage,evenifthismightappearlikeawasteofresources,it'sminimalcomparedtothepossiblenegativeconsequences.

Apackageshouldbeinstalledgloballywhenitprovidesanexecutablecommandthatyourunfromtheshell(CLI),andit'sreusedacrossprojects.

Youcanalsoinstallexecutablecommandslocallyandrunthemusingnpx,butsomepackagesarejustbetterinstalledglobally.

Greatexamplesofpopularglobalpackageswhichyoumightknoware

npm

create-react-app

vue-cli

grunt-cli

mocha

react-native-cli

gatsby-cli

Globalorlocalpackages

78

Page 79: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

forever

nodemon

Youprobablyhavesomepackagesinstalledgloballyalreadyonyoursystem.Youcanseethembyrunning

npmlist-g--depth0

onyourcommandline.

Globalorlocalpackages

79

Page 80: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

npmdependenciesanddevDependenciesWhenisapackageadependency,andwhenisitadevdependency?

Whenyouinstallannpmpackageusing npminstall<package-name>,youareinstallingitasadependency.

Thepackageisautomaticallylistedinthepackage.jsonfile,underthe dependencieslist(asofnpm5:beforeyouhadtomanuallyspecify --save).

Whenyouaddthe -Dflag,or --save-dev,youareinstallingitasadevelopmentdependency,whichaddsittothe devDependencieslist.

Developmentdependenciesareintendedasdevelopment-onlypackages,thatareunneededinproduction.Forexampletestingpackages,webpackorBabel.

Whenyougoinproduction,ifyoutype npminstallandthefoldercontainsa package.jsonfile,theyareinstalled,asnpmassumesthisisadevelopmentdeploy.

Youneedtosetthe --productionflag( npminstall--production)toavoidinstallingthosedevelopmentdependencies.

npmdependenciesanddevDependencies

80

Page 81: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

npxnpxisaverycoolwaytorunNodecode,andprovidesmanyusefulfeatures

Inthispost,Iwanttointroduceaverypowerfulcommandthat'sbeenavailableinnpmstartingversion5.2,releasedinJuly2017:npx.

Ifyoudon'twanttoinstallnpm,youcaninstallnpxasastandalonepackage

npxletsyouruncodebuiltwithNodeandpublishedthroughthenpmregistry.

EasilyrunlocalcommandsNodedevelopersusedtopublishmostoftheexecutablecommandsasglobalpackages,inorderforthemtobeinthepathandexecutableimmediately.

Thiswasapainbecauseyoucouldnotreallyinstalldifferentversionsofthesamecommand.

Running npxcommandnameautomaticallyfindsthecorrectreferenceofthecommandinsidethenode_modulesfolderofaproject,withoutneedingtoknowtheexactpath,andwithoutrequiringthepackagetobeinstalledgloballyandintheuser'spath.

Installation-lesscommandexecutionThereisanothergreatfeatureof npm,whichisallowingtoruncommandswithoutfirstinstallingthem.

Thisisprettyuseful,mostlybecause:

1)youdon'tneedtoinstallanything2)youcanrundifferentversionsofthesamecommand,usingthesyntax@version

Atypicaldemonstrationofusing npxisthroughthe cowsaycommand. cowsaywillprintacowsayingwhatyouwroteinthecommand.Forexample:

cowsay"Hello"willprint

_______

<Hello>

-------

\^__^

\(oo)\_______

(__)\)\/\

||----w|

npx

81

Page 82: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

||||

Now,thisifyouhavethe cowsaycommandgloballyinstalledfromnpmpreviously,otherwiseyou'llgetanerrorwhenyoutrytorunthecommand.

npxallowsyoutorunthatnpmcommandwithouthavingitinstalledlocally:

npxcowsay"Hello"

willdothejob.

Now,thisisafunnyuselesscommand.Otherscenariosinclude:

runningthe vueCLItooltocreatenewapplicationsandrunthem: npxvuecreatemy-vue-app

creatinganewReactappusing create-react-app: npxcreate-react-appmy-react-app

andmanymore.

Oncedownloaded,thedownloadedcodewillbewiped.

RunsomecodeusingadifferentNodeversionUsethe @tospecifytheversion,andcombinethatwiththe nodenpmpackage:

npxnode@6-v#v6.14.3

npxnode@8-v#v8.11.3

Thishelpstoavoidtoolslike nvmortheotherNodeversionmanagementtools.

RunarbitrarycodesnippetsdirectlyfromaURLnpxdoesnotlimityoutothepackagespublishedonthenpmregistry.

YoucanruncodethatsitsinaGitHubgist,forexample:

npxhttps://gist.github.com/zkat/4bc19503fe9e9309e2bfaa2c58074d32

Ofcourse,youneedtobecarefulwhenrunningcodethatyoudonotcontrol,aswithgreatpowercomesgreatresponsibility.

npx

82

Page 83: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

npx

83

Page 84: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheeventloopTheEventLoopisoneofthemostimportantaspectstounderstandaboutJavaScript.Thispostexplainsitinsimpleterms

IntroductionBlockingtheeventloopThecallstackAsimpleeventloopexplanationQueuingfunctionexecutionTheMessageQueueES6JobQueue

IntroductionTheEventLoopisoneofthemostimportantaspectstounderstandaboutJavaScript.

I'veprogrammedforyearswithJavaScript,yetI'veneverfullyunderstoodhowthingsworkunderthehoods.It'scompletelyfinetonotknowthisconceptindetail,butasusual,it'shelpfultoknowhowitworks,andalsoyoumightjustbealittlecuriousatthispoint.

ThispostaimstoexplaintheinnerdetailsofhowJavaScriptworkswithasinglethread,andhowithandlesasynchronousfunctions.

YourJavaScriptcoderunssinglethreaded.Thereisjustonethinghappeningatatime.

Thisisalimitationthat'sactuallyveryhelpful,asitsimplifiesalothowyouprogramwithoutworryingaboutconcurrencyissues.

Youjustneedtopayattentiontohowyouwriteyourcodeandavoidanythingthatcouldblockthethread,likesynchronousnetworkcallsorinfiniteloops.

Ingeneral,inmostbrowsersthereisaneventloopforeverybrowsertab,tomakeeveryprocessisolatedandavoidawebpagewithinfiniteloopsorheavyprocessingtoblockyourentirebrowser.

Theenvironmentmanagesmultipleconcurrenteventloops,tohandleAPIcallsforexample.WebWorkersrunintheirowneventloopaswell.

Youmainlyneedtobeconcernedthatyourcodewillrunonasingleeventloop,andwritecodewiththisthinginmindtoavoidblockingit.

Theeventloop

84

Page 85: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

BlockingtheeventloopAnyJavaScriptcodethattakestoolongtoreturnbackcontroltotheeventloopwillblocktheexecutionofanyJavaScriptcodeinthepage,evenblocktheUIthread,andtheusercannotclickaround,scrollthepage,andsoon.

AlmostalltheI/OprimitivesinJavaScriptarenon-blocking.Networkrequests,Node.jsfilesystemoperations,andsoon.Beingblockingistheexception,andthisiswhyJavaScriptisbasedsomuchoncallbacks,andmorerecentlyonpromisesandasync/await.

ThecallstackThecallstackisaLIFOqueue(LastIn,FirstOut).

Theeventloopcontinuouslychecksthecallstacktoseeifthere'sanyfunctionthatneedstorun.

Whiledoingso,itaddsanyfunctioncallitfindstothecallstackandexecuteseachoneinorder.

Youknowtheerrorstacktraceyoumightbefamiliarwith,inthedebuggerorinthebrowserconsole?Thebrowserlooksupthefunctionnamesinthecallstacktoinformyouwhichfunctionoriginatesthecurrentcall:

Theeventloop

85

Page 86: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

AsimpleeventloopexplanationLet'spickanexample:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

bar()

baz()

}

foo()

Theeventloop

86

Page 87: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thiscodeprints

foo

bar

baz

asexpected.

Whenthiscoderuns,first foo()iscalled.Inside foo()wefirstcall bar(),thenwecallbaz().

Atthispointthecallstacklookslikethis:

Theeventlooponeveryiterationlooksifthere'ssomethinginthecallstack,andexecutesit:

Theeventloop

87

Page 88: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

untilthecallstackisempty.

QueuingfunctionexecutionTheaboveexamplelooksnormal,there'snothingspecialaboutit:JavaScriptfindsthingstoexecute,runstheminorder.

Theeventloop

88

Page 89: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Let'sseehowtodeferafunctionuntilthestackisclear.

Theusecaseof setTimeout(()=>{}),0)istocallafunction,butexecuteitonceeveryotherfunctioninthecodehasexecuted.

Takethisexample:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

setTimeout(bar,0)

baz()

}

foo()

Thiscodeprints,maybesurprisingly:

foo

baz

bar

Whenthiscoderuns,firstfoo()iscalled.Insidefoo()wefirstcallsetTimeout,passing barasanargument,andweinstructittorunimmediatelyasfastasitcan,passing0asthetimer.Thenwecallbaz().

Atthispointthecallstacklookslikethis:

Theeventloop

89

Page 90: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Hereistheexecutionorderforallthefunctionsinourprogram:

Theeventloop

90

Page 91: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Whyisthishappening?

TheMessageQueueWhensetTimeout()iscalled,theBrowserorNode.jsstartthetimer.Oncethetimerexpires,inthiscaseimmediatelyasweput0asthetimeout,thecallbackfunctionisputintheMessageQueue.

Theeventloop

91

Page 92: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheMessageQueueisalsowhereuser-initiatedeventslikeclickorkeyboardevents,orfetchresponsesarequeuedbeforeyourcodehastheopportunitytoreacttothem.OralsoDOMeventslike onLoad.

Theloopgivesprioritytothecallstack,anditfirstprocesseseverythingitfindsinthecallstack,andoncethere'snothinginthere,itgoestopickupthingsintheeventqueue.

Wedon'thavetowaitforfunctionslike setTimeout,fetchorotherthingstodotheirownwork,becausetheyareprovidedbythebrowser,andtheyliveontheirownthreads.Forexample,ifyousetthe setTimeouttimeoutto2seconds,youdon'thavetowait2seconds-thewaithappenselsewhere.

ES6JobQueueECMAScript2015introducedtheconceptoftheJobQueue,whichisusedbyPromises(alsointroducedinES6/ES2015).It'sawaytoexecutetheresultofanasyncfunctionassoonaspossible,ratherthanbeingputattheendofthecallstack.

Promisesthatresolvebeforethecurrentfunctionendswillbeexecutedrightafterthecurrentfunction.

Ifindnicetheanalogyofarollercoasterrideatanamusementpark:themessagequeueputsyoubackinqueuewithafteralltheotherpeopleinthequeue,whilethejobqueueisthefastpassticketthatletsyoutakeanotherriderightafteryoufinishedthepreviousone.

Example:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

setTimeout(bar,0)

newPromise((resolve,reject)=>

resolve('shouldberightafterbaz,beforebar')

).then(resolve=>console.log(resolve))

baz()

}

foo()

Thisprints

foo

Theeventloop

92

Page 93: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

baz

shouldberightafterbaz,beforebar

bar

That'sabigdifferencebetweenPromises(andAsync/await,whichisbuiltonpromises)andplainoldasynchronousfunctionsthrough setTimeout()orotherplatformAPIs.

Theeventloop

93

Page 94: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

nextTickTheNode.jsprocess.nextTickfunctioninteractswiththeeventloopinaspecialway

AsyoutrytounderstandtheNode.jseventloop,oneimportantpartofitisprocess.nextTick().

Everytimetheeventlooptakesafulltrip,wecallitatick.

Whenwepassafunctionto process.nextTick(),weinstructtheenginetoinvokethisfunctionattheendofthecurrentoperation,beforethenexteventlooptickstarts:

process.nextTick(()=>{

//dosomething

})

Theeventloopisbusyprocessingthecurrentfunctioncode.

Whenthisoperationends,theJSenginerunsallthefunctionspassedto nextTickcallsduringthatoperation.

It'sthewaywecantelltheJSenginetoprocessafunctionasynchronously(afterthecurrentfunction),butassoonaspossible,notqueueit.

Calling setTimeout(()=>{},0)willexecutethefunctioninthenexttick,muchlaterthanwhenusing nextTick().

Use nextTick()whenyouwanttomakesurethatinthenexteventloopiterationthatcodeisalreadyexecuted.

nextTick

94

Page 95: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

setImmediateTheNode.jssetImmediatefunctioninteractswiththeeventloopinaspecialway

Whenyouwanttoexecutesomepieceofcodeasynchronously,butassoonaspossible,oneoptionistousethe setImmediate()functionprovidedbyNode.js:

setImmediate(()=>{

//runsomething

})

AnyfunctionpassedasthesetImmediate()argumentisacallbackthat'sexecutedinthenextiterationoftheeventloop.

Howis setImmediate()differentfrom setTimeout(()=>{},0)(passinga0mstimeout),andfrom process.nextTick()?

Afunctionpassedto process.nextTick()isgoingtobeexecutedonthecurrentiterationoftheeventloop,afterthecurrentoperationends.ThismeansitwillalwaysexecutebeforesetTimeoutand setImmediate.

A setTimeout()callbackwitha0msdelayisverysimilarto setImmediate().Theexecutionorderwilldependonvariousfactors,buttheywillbebothruninthenextiterationoftheeventloop.

setImmediate

95

Page 96: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TimersWhenwritingJavaScriptcode,youmightwanttodelaytheexecutionofafunction.LearnhowtousesetTimeoutandsetIntervaltoschedulefunctionsinthefuture

setTimeout()

ZerodelaysetInterval()

RecursivesetTimeout

setTimeout()

WhenwritingJavaScriptcode,youmightwanttodelaytheexecutionofafunction.

Thisisthejobof setTimeout.Youspecifyacallbackfunctiontoexecutelater,andavalueexpressinghowlateryouwantittorun,inmilliseconds:

setTimeout(()=>{

//runsafter2seconds

},2000)

setTimeout(()=>{

//runsafter50milliseconds

},50)

Thissyntaxdefinesanewfunction.Youcancallwhateverotherfunctionyouwantinthere,oryoucanpassanexistingfunctionname,andasetofparameters:

constmyFunction=(firstParam,secondParam)=>{

//dosomething

}

Timers

96

Page 97: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

//runsafter2seconds

setTimeout(myFunction,2000,firstParam,secondParam)

setTimeoutreturnsthetimerid.Thisisgenerallynotused,butyoucanstorethisid,andclearitifyouwanttodeletethisscheduledfunctionexecution:

constid=setTimeout(()=>{

//shouldrunafter2seconds

},2000)

//Ichangedmymind

clearTimeout(id)

Zerodelay

Ifyouspecifythetimeoutdelayto 0,thecallbackfunctionwillbeexecutedassoonaspossible,butafterthecurrentfunctionexecution:

setTimeout(()=>{

console.log('after')

},0)

console.log('before')

willprint beforeafter.

ThisisespeciallyusefultoavoidblockingtheCPUonintensivetasksandletotherfunctionsbeexecutedwhileperformingaheavycalculation,byqueuingfunctionsinthescheduler.

Somebrowsers(IEandEdge)implementa setImmediate()methodthatdoesthissameexactfunctionality,butit'snotstandardandunavailableonotherbrowsers.Butit'sastandardfunctioninNode.js.

setInterval()

setIntervalisafunctionsimilarto setTimeout,withadifference:insteadofrunningthecallbackfunctiononce,itwillrunitforever,atthespecifictimeintervalyouspecify(inmilliseconds):

setInterval(()=>{

//runsevery2seconds

},2000)

Timers

97

Page 98: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thefunctionaboverunsevery2secondsunlessyoutellittostop,using clearInterval,passingittheintervalidthat setIntervalreturned:

constid=setInterval(()=>{

//runsevery2seconds

},2000)

clearInterval(id)

It'scommontocall clearIntervalinsidethesetIntervalcallbackfunction,toletitauto-determineifitshouldrunagainorstop.ForexamplethiscoderunssomethingunlessApp.somethingIWaithasthevalue arrived:

constinterval=setInterval(()=>{

if(App.somethingIWait==='arrived'){

clearInterval(interval)

return

}

//otherwisedothings

},100)

RecursivesetTimeoutsetIntervalstartsafunctioneverynmilliseconds,withoutanyconsiderationaboutwhenafunctionfinisheditsexecution.

Ifafunctiontakesalwaysthesameamountoftime,it'sallfine:

Maybethefunctiontakesdifferentexecutiontimes,dependingonnetworkconditionsforexample:

Andmaybeonelongexecutionoverlapsthenextone:

Timers

98

Page 99: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Toavoidthis,youcanschedulearecursivesetTimeouttobecalledwhenthecallbackfunctionfinishes:

constmyFunction=()=>{

//dosomething

setTimeout(myFunction,1000)

}

setTimeout(

myFunction()

},1000)

toachievethisscenario:

setTimeoutand setIntervalareavailableinNode.js,throughtheTimersmodule.

Node.jsalsoprovides setImmediate(),whichisequivalenttousing setTimeout(()=>{},0),mostlyusedtoworkwiththeNode.jsEventLoop.

Timers

99

Page 100: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

CallbacksJavaScriptissynchronousbydefault,andissinglethreaded.Thismeansthatcodecannotcreatenewthreadsandruninparallel.Findoutwhatasynchronouscodemeansandhowitlookslike

AsynchronicityinProgrammingLanguagesJavaScriptCallbacksHandlingerrorsincallbacksTheproblemwithcallbacksAlternativestocallbacks

AsynchronicityinProgrammingLanguagesComputersareasynchronousbydesign.

Asynchronousmeansthatthingscanhappenindependentlyofthemainprogramflow.

Callbacks

100

Page 101: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Inthecurrentconsumercomputers,everyprogramrunsforaspecifictimeslot,andthenitstopsitsexecutiontoletanotherprogramcontinueitsexecution.Thisthingrunsinacyclesofastthat'simpossibletonotice,andwethinkourcomputersrunmanyprogramssimultaneously,butthisisanillusion(exceptonmultiprocessormachines).

Programsinternallyuseinterrupts,asignalthat'semittedtotheprocessortogaintheattentionofthesystem.

Iwon'tgointotheinternalsofthis,butjustkeepinmindthatit'snormalforprogramstobeasynchronous,andhalttheirexecutionuntiltheyneedattention,andthecomputercanexecuteotherthingsinthemeantime.Whenaprogramiswaitingforaresponsefromthenetwork,itcannothalttheprocessoruntiltherequestfinishes.

Normally,programminglanguagesaresynchronous,andsomeprovideawaytomanageasynchronicity,inthelanguageorthroughlibraries.C,Java,C#,PHP,Go,Ruby,Swift,Python,theyareallsynchronousbydefault.Someofthemhandleasyncbyusingthreads,spawninganewprocess.

JavaScriptJavaScriptissynchronousbydefaultandissinglethreaded.Thismeansthatcodecannotcreatenewthreadsandruninparallel.

Linesofcodeareexecutedinseries,oneafteranother,forexample:

consta=1

constb=2

constc=a*b

console.log(c)

doSomething()

ButJavaScriptwasborninsidethebrowser,itsmainjob,inthebeginning,wastorespondtouseractions,like onClick, onMouseOver, onChange, onSubmitandsoon.Howcoulditdothiswithasynchronousprogrammingmodel?

Theanswerwasinitsenvironment.ThebrowserprovidesawaytodoitbyprovidingasetofAPIsthatcanhandlethiskindoffunctionality.

Morerecently,Node.jsintroducedanon-blockingI/Oenvironmenttoextendthisconcepttofileaccess,networkcallsandsoon.

Callbacks

Callbacks

101

Page 102: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Youcan'tknowwhenauserisgoingtoclickabutton,sowhatyoudois,youdefineaneventhandlerfortheclickevent.Thiseventhandleracceptsafunction,whichwillbecalledwhentheeventistriggered:

document.getElementById('button').addEventListener('click',()=>{

//itemclicked

})

Thisistheso-calledcallback.

Acallbackisasimplefunctionthat'spassedasavaluetoanotherfunction,andwillonlybeexecutedwhentheeventhappens.WecandothisbecauseJavaScripthasfirst-classfunctions,whichcanbeassignedtovariablesandpassedaroundtootherfunctions(calledhigher-orderfunctions)

It'scommontowrapallyourclientcodeina loadeventlisteneronthe windowobject,whichrunsthecallbackfunctiononlywhenthepageisready:

window.addEventListener('load',()=>{

//windowloaded

//dowhatyouwant

})

Callbacksareusedeverywhere,notjustinDOMevents.

Onecommonexampleisbyusingtimers:

setTimeout(()=>{

//runsafter2seconds

},2000)

XHRrequestsalsoacceptacallback,inthisexamplebyassigningafunctiontoapropertythatwillbecalledwhenaparticulareventoccurs(inthiscase,thestateoftherequestchanges):

constxhr=newXMLHttpRequest()

xhr.onreadystatechange=()=>{

if(xhr.readyState===4){

xhr.status===200?console.log(xhr.responseText):console.error('error')

}

}

xhr.open('GET','https://yoursite.com')

xhr.send()

Handlingerrorsincallbacks

Callbacks

102

Page 103: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Howdoyouhandleerrorswithcallbacks?OneverycommonstrategyistousewhatNode.jsadopted:thefirstparameterinanycallbackfunctionistheerrorobject:error-firstcallbacks

Ifthereisnoerror,theobjectis null.Ifthereisanerror,itcontainssomedescriptionoftheerrorandotherinformation.

fs.readFile('/file.json',(err,data)=>{

if(err!==null){

//handleerror

console.log(err)

return

}

//noerrors,processdata

console.log(data)

})

TheproblemwithcallbacksCallbacksaregreatforsimplecases!

Howevereverycallbackaddsalevelofnesting,andwhenyouhavelotsofcallbacks,thecodestartstobecomplicatedveryquickly:

window.addEventListener('load',()=>{

document.getElementById('button').addEventListener('click',()=>{

setTimeout(()=>{

items.forEach(item=>{

//yourcodehere

})

},2000)

})

})

Thisisjustasimple4-levelscode,butI'veseenmuchmorelevelsofnestingandit'snotfun.

Howdowesolvethis?

AlternativestocallbacksStartingwithES6,JavaScriptintroducedseveralfeaturesthathelpuswithasynchronouscodethatdonotinvolveusingcallbacks:

Promises(ES6)Async/Await(ES8)

Callbacks

103

Page 104: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Callbacks

104

Page 105: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

PromisesPromisesareonewaytodealwithasynchronouscodeinJavaScript,withoutwritingtoomanycallbacksinyourcode.

IntroductiontopromisesHowpromiseswork,inbriefWhichJSAPIusepromises?

CreatingapromiseConsumingapromiseChainingpromises

ExampleofchainingpromisesHandlingerrors

CascadingerrorsOrchestratingpromises

Promise.all()

Promise.race()

CommonerrorsUncaughtTypeError:undefinedisnotapromise

IntroductiontopromisesApromiseiscommonlydefinedasaproxyforavaluethatwilleventuallybecomeavailable.

Promisesareonewaytodealwithasynchronouscode,withoutwritingtoomanycallbacksinyourcode.

Althoughbeingaroundsinceyears,theyhavebeenstandardizedandintroducedinES2015,andnowtheyhavebeensupersededinES2017byasyncfunctions.

AsyncfunctionsusethepromisesAPIastheirbuildingblock,sounderstandingthemisfundamentalevenifinnewercodeyou'lllikelyuseasyncfunctionsinsteadofpromises.

Howpromiseswork,inbrief

Onceapromisehasbeencalled,itwillstartinpendingstate.Thismeansthatthecallerfunctioncontinuestheexecution,whileitwaitsforthepromisetodoitsownprocessing,andgivethecallerfunctionsomefeedback.

Promises

105

Page 106: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Atthispoint,thecallerfunctionwaitsforittoeitherreturnthepromiseinaresolvedstate,orinarejectedstate,butasyouknowJavaScriptisasynchronous,sothefunctioncontinuesitsexecutionwhilethepromisedoesitwork.

WhichJSAPIusepromises?

Inadditiontoyourowncodeandlibrariescode,promisesareusedbystandardmodernWebAPIssuchas:

theBatteryAPItheFetchAPIServiceWorkers

It'sunlikelythatinmodernJavaScriptyou'llfindyourselfnotusingpromises,solet'sstartdivingrightintothem.

CreatingapromiseThePromiseAPIexposesaPromiseconstructor,whichyouinitializeusing newPromise():

letdone=true

constisItDoneYet=newPromise(

(resolve,reject)=>{

if(done){

constworkDone='HereisthethingIbuilt'

resolve(workDone)

}else{

constwhy='Stillworkingonsomethingelse'

reject(why)

}

}

)

Asyoucanseethepromisechecksthe doneglobalconstant,andifthat'strue,wereturnaresolvedpromise,otherwisearejectedpromise.

Using resolveand rejectwecancommunicatebackavalue,intheabovecasewejustreturnastring,butitcouldbeanobjectaswell.

Consumingapromise

Promises

106

Page 107: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Inthelastsection,weintroducedhowapromiseiscreated.

Nowlet'sseehowthepromisecanbeconsumedorused.

constisItDoneYet=newPromise(

//...

)

constcheckIfItsDone=()=>{

isItDoneYet

.then((ok)=>{

console.log(ok)

})

.catch((err)=>{

console.error(err)

})

}

Running checkIfItsDone()willexecutethe isItDoneYet()promiseandwillwaitforittoresolve,usingthe thencallback,andifthereisanerror,itwillhandleitinthe catchcallback.

ChainingpromisesApromisecanbereturnedtoanotherpromise,creatingachainofpromises.

AgreatexampleofchainingpromisesisgivenbytheFetchAPI,alayerontopoftheXMLHttpRequestAPI,whichwecanusetogetaresourceandqueueachainofpromisestoexecutewhentheresourceisfetched.

TheFetchAPIisapromise-basedmechanism,andcalling fetch()isequivalenttodefiningourownpromiseusing newPromise().

Exampleofchainingpromises

conststatus=(response)=>{

if(response.status>=200&&response.status<300){

returnPromise.resolve(response)

}

returnPromise.reject(newError(response.statusText))

}

constjson=(response)=>response.json()

fetch('/todos.json')

.then(status)

Promises

107

Page 108: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

.then(json)

.then((data)=>{console.log('RequestsucceededwithJSONresponse',data)})

.catch((error)=>{console.log('Requestfailed',error)})

Inthisexample,wecall fetch()togetalistofTODOitemsfromthe todos.jsonfilefoundinthedomainroot,andwecreateachainofpromises.

Running fetch()returnsaresponse,whichhasmanyproperties,andwithinthosewereference:

status,anumericvaluerepresentingtheHTTPstatuscodestatusText,astatusmessage,whichis OKiftherequestsucceeded

responsealsohasa json()method,whichreturnsapromisethatwillresolvewiththecontentofthebodyprocessedandtransformedintoJSON.

Sogiventhosepremises,thisiswhathappens:thefirstpromiseinthechainisafunctionthatwedefined,called status(),thatcheckstheresponsestatusandifit'snotasuccessresponse(between200and299),itrejectsthepromise.

Thisoperationwillcausethepromisechaintoskipallthechainedpromiseslistedandwillskipdirectlytothe catch()statementatthebottom,loggingthe Requestfailedtextalongwiththeerrormessage.

Ifthatsucceedsinstead,itcallsthejson()functionwedefined.Sincethepreviouspromise,whensuccessful,returnedthe responseobject,wegetitasaninputtothesecondpromise.

Inthiscase,wereturnthedataJSONprocessed,sothethirdpromisereceivestheJSONdirectly:

.then((data)=>{

console.log('RequestsucceededwithJSONresponse',data)

})

andwesimplylogittotheconsole.

HandlingerrorsIntheexample,intheprevioussection,wehada catchthatwasappendedtothechainofpromises.

Whenanythinginthechainofpromisesfailsandraisesanerrororrejectsthepromise,thecontrolgoestothenearest catch()statementdownthechain.

Promises

108

Page 109: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

newPromise((resolve,reject)=>{

thrownewError('Error')

})

.catch((err)=>{console.error(err)})

//or

newPromise((resolve,reject)=>{

reject('Error')

})

.catch((err)=>{console.error(err)})

Cascadingerrors

Ifinsidethe catch()youraiseanerror,youcanappendasecond catch()tohandleit,andsoon.

newPromise((resolve,reject)=>{

thrownewError('Error')

})

.catch((err)=>{thrownewError('Error')})

.catch((err)=>{console.error(err)})

Orchestratingpromises

Promise.all()

Ifyouneedtosynchronizedifferentpromises, Promise.all()helpsyoudefinealistofpromises,andexecutesomethingwhentheyareallresolved.

Example:

constf1=fetch('/something.json')

constf2=fetch('/something2.json')

Promise.all([f1,f2]).then((res)=>{

console.log('Arrayofresults',res)

})

.catch((err)=>{

console.error(err)

})

TheES2015destructuringassignmentsyntaxallowsyoutoalsodo

Promise.all([f1,f2]).then(([res1,res2])=>{

Promises

109

Page 110: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

console.log('Results',res1,res2)

})

Youarenotlimitedtousing fetchofcourse,anypromiseisgoodtogo.

Promise.race()

Promise.race()runswhenthefirstofthepromisesyoupasstoitresolves,anditrunstheattachedcallbackjustonce,withtheresultofthefirstpromiseresolved.

Example:

constfirst=newPromise((resolve,reject)=>{

setTimeout(resolve,500,'first')

})

constsecond=newPromise((resolve,reject)=>{

setTimeout(resolve,100,'second')

})

Promise.race([first,second]).then((result)=>{

console.log(result)//second

})

Commonerrors

UncaughtTypeError:undefinedisnotapromise

Ifyougetthe UncaughtTypeError:undefinedisnotapromiseerrorintheconsole,makesureyouuse newPromise()insteadofjust Promise()

Promises

110

Page 111: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

async/awaitDiscoverthemodernapproachtoasynchronousfunctionsinJavaScript.JavaScriptevolvedinaveryshorttimefromcallbackstoPromises,andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax

IntroductionWhywereasync/awaitintroduced?HowitworksAquickexamplePromiseallthethingsThecodeismuchsimplertoreadMultipleasyncfunctionsinseriesEasierdebugging

IntroductionJavaScriptevolvedinaveryshorttimefromcallbackstopromises(ES2015),andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax.

Asyncfunctionsareacombinationofpromisesandgenerators,andbasically,theyareahigherlevelabstractionoverpromises.Letmerepeat:async/awaitisbuiltonpromises.

Whywereasync/awaitintroduced?Theyreducetheboilerplatearoundpromises,andthe"don'tbreakthechain"limitationofchainingpromises.

WhenPromiseswereintroducedinES2015,theyweremeanttosolveaproblemwithasynchronouscode,andtheydid,butoverthe2yearsthatseparatedES2015andES2017,itwasclearthatpromisescouldnotbethefinalsolution.

Promiseswereintroducedtosolvethefamouscallbackhellproblem,buttheyintroducedcomplexityontheirown,andsyntaxcomplexity.

Theyweregoodprimitivesaroundwhichabettersyntaxcouldbeexposedtothedevelopers,sowhenthetimewasrightwegotasyncfunctions.

Theymakethecodelooklikeit'ssynchronous,butit'sasynchronousandnon-blockingbehindthescenes.

async/await

111

Page 112: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowitworksAnasyncfunctionreturnsapromise,likeinthisexample:

constdoSomethingAsync=()=>{

returnnewPromise((resolve)=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

}

Whenyouwanttocallthisfunctionyouprepend await,andthecallingcodewillstopuntilthepromiseisresolvedorrejected.Onecaveat:theclientfunctionmustbedefinedasasync.Here'sanexample:

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

AquickexampleThisisasimpleexampleofasync/awaitusedtorunafunctionasynchronously:

constdoSomethingAsync=()=>{

returnnewPromise((resolve)=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

}

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

console.log('Before')

doSomething()

console.log('After')

Theabovecodewillprintthefollowingtothebrowserconsole:

Before

After

Ididsomething//after3s

Promiseallthethings

async/await

112

Page 113: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Prependingthe asynckeywordtoanyfunctionmeansthatthefunctionwillreturnapromise.

Evenifit'snotdoingsoexplicitly,itwillinternallymakeitreturnapromise.

Thisiswhythiscodeisvalid:

constaFunction=async()=>{

return'test'

}

aFunction().then(alert)//Thiswillalert'test'

andit'sthesameas:

constaFunction=async()=>{

returnPromise.resolve('test')

}

aFunction().then(alert)//Thiswillalert'test'

ThecodeismuchsimplertoreadAsyoucanseeintheexampleabove,ourcodelooksverysimple.Compareittocodeusingplainpromises,withchainingandcallbackfunctions.

Andthisisaverysimpleexample,themajorbenefitswillarisewhenthecodeismuchmorecomplex.

Forexamplehere'showyouwouldgetaJSONresource,andparseit,usingpromises:

constgetFirstUserData=()=>{

returnfetch('/users.json')//getuserslist

.then(response=>response.json())//parseJSON

.then(users=>users[0])//pickfirstuser

.then(user=>fetch(`/users/${user.name}`))//getuserdata

.then(userResponse=>response.json())//parseJSON

}

getFirstUserData()

Andhereisthesamefunctionalityprovidedusingawait/async:

constgetFirstUserData=async()=>{

constresponse=awaitfetch('/users.json')//getuserslist

constusers=awaitresponse.json()//parseJSON

constuser=users[0]//pickfirstuser

constuserResponse=awaitfetch(`/users/${user.name}`)//getuserdata

async/await

113

Page 114: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

constuserData=awaituser.json()//parseJSON

returnuserData

}

getFirstUserData()

MultipleasyncfunctionsinseriesAsyncfunctionscanbechainedveryeasily,andthesyntaxismuchmorereadablethanwithplainpromises:

constpromiseToDoSomething=()=>{

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),10000)

})

}

constwatchOverSomeoneDoingSomething=async()=>{

constsomething=awaitpromiseToDoSomething()

returnsomething+'andIwatched'

}

constwatchOverSomeoneWatchingSomeoneDoingSomething=async()=>{

constsomething=awaitwatchOverSomeoneDoingSomething()

returnsomething+'andIwatchedaswell'

}

watchOverSomeoneWatchingSomeoneDoingSomething().then((res)=>{

console.log(res)

})

Willprint:

IdidsomethingandIwatchedandIwatchedaswell

EasierdebuggingDebuggingpromisesishardbecausethedebuggerwillnotstepoverasynchronouscode.

Async/awaitmakesthisveryeasybecausetothecompilerit'sjustlikesynchronouscode.

async/await

114

Page 115: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheNodeEventEmitterHowtoworkwithcustomeventsinNode

IfyouworkedwithJavaScriptinthebrowser,youknowhowmuchoftheinteractionoftheuserishandledthroughevents:mouseclicks,keyboardbuttonpresses,reactingtomousemovements,andsoon.

Onthebackendside,Nodeoffersustheoptiontobuildasimilarsystemusingthe eventsmodule.

Thismodule,inparticular,offersthe EventEmitterclass,whichwe'llusetohandleourevents.

Youinitializethatusing

consteventEmitter=require('events').EventEmitter()

Thisobjectexposes,amongmanyothers,the onand emitmethods.

emitisusedtotriggeraneventonisusedtoaddacallbackfunctionthat'sgoingtobeexecutedwhentheeventistriggered

Forexample,let'screatea startevent,andasamatterofprovidingasample,wereacttothatbyjustloggingtotheconsole:

eventEmitter.on('start',()=>{

console.log('started')

})

Whenwerun

eventEmitter.emit('start')

theeventhandlerfunctionistriggered,andwegettheconsolelog.

Youcanpassargumentstotheeventhandlerbypassingthemasadditionalargumentstoemit():

eventEmitter.on('start',(number)=>{

console.log(`started${number}`)

})

eventEmitter.emit('start',23)

TheNodeEventEmitter

115

Page 116: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Multiplearguments:

eventEmitter.on('start',(start,end)=>{

console.log(`startedfrom${start}to${end}`)

})

eventEmitter.emit('start',1,100)

TheEventEmitterobjectalsoexposesseveralothermethodstointeractwithevents,like

once():addaone-timelistenerremoveListener()/ off():removeaneventlistenerfromaneventremoveAllListeners():removealllistenersforanevent

Youcanreadalltheirdetailsontheeventsmodulepageathttps://nodejs.org/api/events.html

TheNodeEventEmitter

116

Page 117: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HTTPAdetaileddescriptionofhowtheHTTPprotocol,andtheWeb,work

HTTP(HyperTextTransferProtocol)isoneoftheapplicationprotocolsofTCP/IP,thesuiteofprotocolsthatpowerstheInternet.

Letmefixthat:it'snotoneoftheprotocols,it'sthemostsuccessfulandpopularone,byallmeans.

HTTPiswhatmakestheWorldWideWebwork,givingbrowsersalanguagetocommunicatetoremoteserversthathostwebpages.

HTTPwasfirststandardizedin1991,asaresultoftheworkthatTimBerners-LeedidatCERN,theEuropeanCenterofNuclearResearch,since1989.

Thegoalwastoallowresearcherstoeasilyexchangeandinterlinktheirpapers.Itwasmeantasawayforthescientificcommunitytoworkbetter.

BackthentheinternetmainapplicationsbasicallyconsistedinFTP(theFileTransferProtocol),EmailandUsenet(newsgroups,todayalmostabandoned).

In1993Mosaic,thefirstgraphicalwebbrowser,wasreleased,andthingsskyrocketedfromthere.

TheWebbecamethekillerappoftheInternet.

OvertimetheWebandtheecosystemaroundithavedramaticallyevolved,butthebasicsstillremain.Oneexampleofevolution:HTTPnowpowers,inadditiontowebpages,RESTAPIs,onecommonwaytoprogrammaticallyaccessaserviceovertheInternet.

HTTPgotaminorrevisionin1997withHTTP/1.1,andin2015itssuccessor,HTTP/2,wasstandardizedandit'snowbeingimplementedbythemajorWebServersusedacrosstheglobe.

TheHTTPprotocolisconsideredinsecure,justlikeanyotherprotocol(SMTP,FTP..)notservedoveranencryptedconnection.ThisiswhythereisabigpushnowadaystowardsusingHTTPS,whichisHTTPservedoverTLS.

Thatsaid,thebuildingblocksofHTTP/2andHTTPShavetheirrootsinHTTP,andinthisarticleI'llintroducehowHTTPworks.

HTMLdocuments

HTTP

117

Page 118: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HTTPisthewaywebbrowserslikeChrome,Firefox,Edgeandmanyothers(alsocalledclientsfromhereon)communicatewithwebservers.

ThenameHyperTextTransferProtocolderivesfromtheneedoftransferringnotjustfiles,likeinFTP-the"FileTransferProtocol",buthypertexts,whichwouldbewrittenusingHTML,andthenrepresentedgraphicallybythebrowserwithanicepresentationandinteractivelinks.

Linkswerethedrivingforcethatdroveadoption,alongwiththeeaseofcreationofnewwebpages.

HTTPiswhattransferthosehypertextfiles(andaswe'llseealsoimagesandotherfiletypes)overthenetwork.

HyperlinksInsideawebbrowser,adocumentcanpointtoanotherdocumentusinglinks.

Alinkiscomposedbyafirstpartthatdeterminestheprotocolandtheserveraddress,eitherthroughadomainnameoranIP.

ThispartisnotuniquetoHTTP,ofcourse.

Thenthere'sthedocumentpart.Anythingappendedtotheaddresspartrepresentsthedocumentpath.

Forexample,thisdocumentaddressis https://flaviocopes.com/http/:

httpsistheprotocol.flaviocopes.comisthedomainnamethatpointstomyserver/http/isthedocumentURLrelativetotheserverrootpath.

Thepathcanbenested: https://flaviocopes.com/page/privacy/andinthiscasethedocumentURLis /page/privacy.

Thewebserverisresponsibleforinterpretingtherequestand,onceanalyzed,servingthecorrectresponse.

ArequestWhat'sinarequest?

ThefirstthingistheURL,whichwe'vealreadyseenbefore.

Whenweenteranaddressandpressenterinourbrowser,underthehoodstheserversendstothecorrectIPaddressarequestlikethis:

HTTP

118

Page 119: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

GET/a-page

where/a-pageistheURLyourequested.

ThesecondthingistheHTTPmethod(alsocalledverb).

HTTPintheearlydaysdefined3ofthem:

GET

POST

HEAD

andHTTP/1.1introduced

PUT

DELETE

OPTIONS

TRACE

We'llseethemindetailinaminute.

ThethirdthingthatcomposesarequestisasetofHTTPheaders.

Headersareasetof key:valuepairsthatareusedtocommunicatetotheserver-specificinformationthatispredefined,sotheservercanknowwhatwemean.

IdescribedthemindetailintheHTTPrequestheaderslist.

Givethatlistaquicklook.Allofthoseheadersareoptional,except Host.

HTTPmethods

GET

GETisthemostusedmethodhere.It'stheonethat'susedwhenyoutypeanURLinthebrowseraddressbar,orwhenyouclickalink.

Itaskstheservertosendtherequestedresourceasaresponse.

HEAD

HEADisjustlikeGET,buttellstheservertonotsendtheresponsebodyback.Justtheheaders.

HTTP

119

Page 120: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

POST

TheclientusesthePOSTmethodtosenddatatotheserver.It'stypicallyusedinforms,forexample,butalsowheninteractingwithaRESTAPI.

PUT

ThePUTmethodisintendedtocreatearesourceatthatspecificURL,withtheparameterspassedintherequestbody.MainlyusedinRESTAPIs

DELETE

TheDELETEmethodiscalledagainstanURLtorequestdeletionofthatresource.MainlyusedinRESTAPIs

OPTIONS

WhenaserverreceivesanOPTIONSrequestitshouldsendbackthelistofHTTPmethodsallowedforthatspecificURL.

TRACE

Returnsbacktotheclienttherequestthathasbeenreceived.Usedfordebuggingordiagnosticpurposes.

HTTPClient/ServercommunicationHTTP,asmostoftheprotocolsthatbelongtotheTCP/IPsuite,isastatelessprotocol.

Servershavenoideawhat'sthecurrentstateoftheclient.Alltheycareaboutisthattheygetrequestandtheyneedtofulfillthem.

Anypriorrequestismeaninglessinthiscontext,andthismakesitpossibleforawebservertobeveryfast,asthere'slesstoprocess,andalsoitgivesitbandwidthtohandlealotofconcurrentrequests.

HTTPisalsoverylean,andcommunicationisveryfastintermsofoverhead.ThiscontrastswiththeprotocolsthatwerethemostusedatthetimeHTTPwasintroduced:TCPandPOP/SMTP,themailprotocols,whichinvolvelotsofhandshakingandconfirmationsonthereceivingends.

HTTP

120

Page 121: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Graphicalbrowsersabstractallthiscommunication,butwe'llillustrateithereforlearningpurposes.

Amessageiscomposedbyafirstline,whichstartswiththeHTTPmethod,thencontainstheresourcerelativepath,andtheprotocolversion:

GET/a-pageHTTP/1.1

Afterthat,weneedtoaddtheHTTPrequestheaders.Asmentionedabove,therearemanyheaders,buttheonlymandatoryoneis Host:

GET/a-pageHTTP/1.1

Host:flaviocopes.com

Howcanyoutestthis?Usingtelnet.Thisisacommand-linetoolthatletsusconnecttoanyserverandsenditcommands.

Openyourterminal,andtype telnetflaviocopes.com80

Thiswillopenaterminal,thattellsyou

Trying178.128.202.129...

Connectedtoflaviocopes.com.

Escapecharacteris'^]'.

YouareconnectedtotheNetlifywebserverthatpowersmyblog.Youcannowtype:

GET/axios/HTTP/1.1

Host:flaviocopes.com

andpressenteronanemptylinetofiretherequest.

Theresponsewillbe:

HTTP/1.1301MovedPermanently

Cache-Control:public,max-age=0,must-revalidate

Content-Length:46

Content-Type:text/plain

Date:Sun,29Jul201814:07:07GMT

Location:https://flaviocopes.com/axios/

Age:0

Connection:keep-alive

Server:Netlify

Redirectingtohttps://flaviocopes.com/axios/

HTTP

121

Page 122: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

See,thisisanHTTPresponsewegotbackfromtheserver.It'sa301MovedPermanentlyrequest.SeetheHTTPstatuscodeslisttoknowmoreaboutthestatuscodes.

Itbasicallytellsustheresourcehaspermanentlymovedtoanotherlocation.

Why?Becauseweconnectedtoport80,whichisthedefaultforHTTP,butonmyserverIsetupanautomaticredirectiontoHTTPS.

Thenewlocationisspecifiedinthe LocationHTTPresponseheader.

Thereareotherheaders,alldescribedintheHTTPresponseheaderslist.

Inboththerequestandtheresponse,anemptylineseparatestherequestheaderfromtherequestbody.Therequestbodyinthiscasecontainsthestring

Redirectingtohttps://flaviocopes.com/axios/

whichis46byteslong,asspecifiedinthe Content-Lengthheader.Itisshowninthebrowserwhenyouopenthepage,whileitautomaticallyredirectsyoutothecorrectlocation.

Inthiscasewe'reusingtelnet,thelow-leveltoolthatwecanusetoconnecttoanyserver,sowecan'thaveanykindofautomaticredirect.

Let'sdothisprocessagain,nowconnectingtoport443,whichisthedefaultportoftheHTTPSprotocol.Wecan'tusetelnetbecauseoftheSSLhandshakethatmusthappen.

Let'skeepthingssimpleanduse curl,anothercommand-linetool.WecannotdirectlytypetheHTTPrequest,butwe'llseetheresponse:

curl-ihttps://flaviocopes.com/axios/

thisiswhatwe'llgetinreturn:

HTTP/1.1200OK

Cache-Control:public,max-age=0,must-revalidate

Content-Type:text/html;charset=UTF-8

Date:Sun,29Jul201814:20:45GMT

Etag:"de3153d6eacef2299964de09db154b32-ssl"

Strict-Transport-Security:max-age=31536000

Age:152

Content-Length:9797

Connection:keep-alive

Server:Netlify

<!DOCTYPEhtml>

<htmlprefix="og:http://ogp.me/ns#"lang="en">

<head>

<metacharset="utf-8">

HTTP

122

Page 123: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

<metahttp-equiv="X-UA-Compatible"content="IE=edge">

<title>HTTPrequestsusingAxios</title>

....

Icuttheresponse,butyoucanseethattheHTMLofthepageisbeingreturnednow.

OtherresourcesAnHTTPserverwillnotjusttransferHTMLfiles,buttypicallyitwillalsoserveotherfiles:CSS,JS,SVG,PNG,JPG,lotsofdifferentfiletypes.

Thisdependsontheconfiguration.

HTTPisperfectlycapableoftransferringthosefilesaswell,andtheclientwillknowaboutthefiletype,thusinterpretthemintherightway.

Thisishowthewebworks:whenanHTMLpageisretrievedbythebrowser,it'sinterpretedandanyotherresourceitneedstodisplayproperty(CSS,JavaScript,images..)isretrievedthroughadditionalHTTPrequeststothesameserver.

HTTP

123

Page 124: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowHTTPRequestsworkWhathappenswhenyoutypeanURLinthebrowser,fromstarttofinish

TheHTTPprotocolIanalyzeURLrequestsonlyThingsrelatetomacOS/LinuxDNSLookupphase

gethostbynameTCPrequesthandshakingSendingtherequest

TherequestlineTherequestheaderTherequestbody

TheresponseParsetheHTML

ThisarticledescribeshowbrowsersperformpagerequestsusingtheHTTP/1.1protocol

Ifyoueverdidaninterview,youmighthavebeenasked:"whathappenswhenyoutypesomethingintotheGooglesearchboxandpressenter".

It'soneofthemostpopularquestionsyougetasked.Peoplejustwanttoseeifyoucanexplainsomeratherbasicconceptsandifyouhaveanycluehowtheinternetactuallyworks.

Inthispost,I'llanalyzewhathappenswhenyoutypeanURLintheaddressbarofyourbrowserandpressenter.

It'saveryinterestingtopictodissectinablogpost,asittouchesmanytechnologiesIcandiveintoinseparateposts.

Thisistechthatisveryrarelychanged,andpowersonethemostcomplexandwideecosystemseverbuiltbyhumans.

TheHTTPprotocolFirst,ImentionHTTPSinparticularbecausethingsaredifferentfromanHTTPSconnection.

IanalyzeURLrequestsonly

HowHTTPRequestswork

124

Page 125: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ModernbrowsershavethecapabilityofknowingifthethingyouwroteintheaddressbarisanactualURLorasearchterm,andtheywillusethedefaultsearchengineifit'snotavalidURL.

IassumeyoutypeanactualURL.

WhenyouentertheURLandpressenter,thebrowserfirstbuildsthefullURL.

Ifyoujustenteredadomain,like flaviocopes.com,thebrowserbydefaultwillprependHTTP://toit,defaultingtotheHTTPprotocol.

ThingsrelatetomacOS/LinuxJustFYI.Windowsmightdosomethingsslightlydifferently.

DNSLookupphaseThebrowserstartstheDNSlookuptogettheserverIPaddress.

Thedomainnameisahandyshortcutforushumans,buttheinternetisorganizedinsuchawaythatcomputerscanlookuptheexactlocationofaserverthroughitsIPaddress,whichisasetofnumberslike 222.324.3.1(IPv4).

First,itcheckstheDNSlocalcache,toseeifthedomainhasalreadybeenresolvedrecently.

ChromehasahandyDNScachevisualizeryoucanseeatchrome://net-internals/#dns

Ifnothingisfoundthere,thebrowserusestheDNSresolver,usingthe gethostbynamePOSIXsystemcalltoretrievethehostinformation.

gethostbyname

gethostbynamefirstlooksinthelocalhostsfile,whichonmacOSorLinuxislocatedin/etc/hosts,toseeifthesystemprovidestheinformationlocally.

Ifthisdoesnotgiveanyinformationaboutthedomain,thesystemmakesarequesttotheDNSserver.

TheaddressoftheDNSserverisstoredinthesystempreferences.

Thoseare2popularDNSservers:

8.8.8.8:theGooglepublicDNSserver1.1.1.1:theCloudFlareDNSserver

MostpeopleusetheDNSserverprovidedbytheirinternetprovider.

HowHTTPRequestswork

125

Page 126: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ThebrowserperformstheDNSrequestusingtheUDPprotocol.

TCPandUDParetwoofthefoundationalprotocolsofcomputernetworking.Theysitatthesameconceptuallevel,butTCPisconnection-oriented,whileUDPisaconnectionlessprotocol,morelightweight,usedtosendmessageswithlittleoverhead.

HowtheUDPrequestisperformedisnotinthescopeofthistutorial

TheDNSservermighthavethedomainIPinthecache.Itnot,itwillasktherootDNSserver.That'sasystem(composedof13actualservers,distributedacrosstheplanet)thatdrivestheentireinternet.

TheDNSserverdoesnotknowtheaddressofeachandeverydomainnameontheplanet.

Whatitknowsiswherethetop-levelDNSresolversare.

Atop-leveldomainisthedomainextension: .com, .it, .pizzaandsoon.

OncetherootDNSserverreceivestherequest,itforwardstherequesttothattop-leveldomain(TLD)DNSserver.

Sayyouarelookingfor flaviocopes.com.TherootdomainDNSserverreturnstheIPofthe.comTLDserver.

NowourDNSresolverwillcachetheIPofthatTLDserver,soitdoesnothavetoasktherootDNSserveragainforit.

TheTLDDNSserverwillhavetheIPaddressesoftheauthoritativeNameServersforthedomainwearelookingfor.

How?Whenyoubuyadomain,thedomainregistrarsendstheappropriateTDLthenameservers.Whenyouupdatethenameservers(forexample,whenyouchangethehostingprovider),thisinformationwillbeautomaticallyupdatedbyyourdomainregistrar.

ThosearetheDNSserversofthehostingprovider.Theyareusuallymorethan1,toserveasbackup.

Forexample:

ns1.dreamhost.com

ns2.dreamhost.com

ns3.dreamhost.com

TheDNSresolverstartswiththefirst,andtriestoasktheIPofthedomain(withthesubdomain,too)youarelookingfor.

ThatistheultimatesourceoftruthfortheIPaddress.

HowHTTPRequestswork

126

Page 127: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

NowthatwehavetheIPaddress,wecangooninourjourney.

TCPrequesthandshakingWiththeserverIPaddressavailable,nowthebrowsercaninitiateaTCPconnectiontothat.

ATCPconnectionrequiresabitofhandshakingbeforeitcanbefullyinitializedandyoucanstartsendingdata.

Oncetheconnectionisestablished,wecansendtherequest

SendingtherequestTherequestisaplaintextdocumentstructuredinaprecisewaydeterminedbythecommunicationprotocol.

It'scomposedof3parts:

therequestlinetherequestheadertherequestbody

Therequestline

Therequestlinesets,onasingleline:

theHTTPmethodtheresourcelocationtheprotocolversion

Example:

GET/HTTP/1.1

Therequestheader

Therequestheaderisasetof field:valuepairsthatsetcertainvalues.

Thereare2mandatoryfields,oneofwhichis Host,andtheotheris Connection,whilealltheotherfieldsareoptional:

Host:flaviocopes.com

Connection:close

HowHTTPRequestswork

127

Page 128: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Hostindicatesthedomainnamewhichwewanttotarget,while Connectionisalwayssettocloseunlesstheconnectionmustbekeptopen.

Someofthemostusedheaderfieldsare:

Origin

Accept

Accept-Encoding

Cookie

Cache-Control

Dnt

butmanymoreexist.

Theheaderpartisterminatedbyablankline.

Therequestbody

Therequestbodyisoptional,notusedinGETrequestsbutverymuchusedinPOSTrequestsandsometimesinotherverbstoo,anditcancontaindatainJSONformat.

Sincewe'renowanalyzingaGETrequest,thebodyisblankandwe'llnotlookmoreintoit.

TheresponseOncetherequestissent,theserverprocessesitandsendsbackaresponse.

Theresponsestartswiththestatuscodeandthestatusmessage.Iftherequestissuccessfulandreturnsa200,itwillstartwith:

200OK

Therequestmightreturnadifferentstatuscodeandmessage,likeoneofthese:

404NotFound

403Forbidden

301MovedPermanently

500InternalServerError

304NotModified

401Unauthorized

TheresponsethencontainsalistofHTTPheadersandtheresponsebody(which,sincewe'remakingtherequestinthebrowser,isgoingtobeHTML)

HowHTTPRequestswork

128

Page 129: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ParsetheHTMLThebrowsernowhasreceivedtheHTMLandstartstoparseit,andwillrepeattheexactsameprocesswedidnotforalltheresourcesrequiredbythepage:

CSSfilesimagesthefaviconJavaScriptfiles...

Howbrowsersrenderthepagethenisoutofthescope,butit'simportanttounderstandthattheprocessIdescribedisnotjustfortheHTMLpages,butforanyitemthat'sservedoverHTTP.

HowHTTPRequestswork

129

Page 130: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

BuildanHTTPserverHowtobuildanHTTPserverwithNode.js

HereistheHTTPwebserverweusedastheNodeHelloWorldapplicationintheNode.jsintroduction

consthttp=require('http')

constport=3000

constserver=http.createServer((req,res)=>{

res.statusCode=200

res.setHeader('Content-Type','text/plain')

res.end('HelloWorld\n')

})

server.listen(port,()=>{

console.log(`Serverrunningathttp://${hostname}:${port}/`)

})

Let'sanalyzeitbriefly.Weincludethe httpmodule.

WeusethemoduletocreateanHTTPserver.

Theserverissettolistenonthespecifiedport, 3000.Whentheserverisready,the listencallbackfunctioniscalled.

Thecallbackfunctionwepassistheonethat'sgoingtobeexecuteduponeveryrequestthatcomesin.Wheneveranewrequestisreceived,the requesteventiscalled,providingtwoobjects:arequest(an http.IncomingMessageobject)andaresponse(an http.ServerResponseobject).

requestprovidestherequestdetails.Throughit,weaccesstherequestheadersandrequestdata.

responseisusedtopopulatethedatawe'regoingtoreturntotheclient.

Inthiscasewith

res.statusCode=200

wesetthestatusCodepropertyto200,toindicateasuccessfulresponse.

WealsosettheContent-Typeheader:

BuildanHTTPserver

130

Page 131: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

res.setHeader('Content-Type','text/plain')

andweendclosetheresponse,addingthecontentasanargumentto end():

res.end('HelloWorld\n')

BuildanHTTPserver

131

Page 132: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

MakingHTTPrequestsHowtoperformHTTPrequestswithNode.jsusingGET,POST,PUTandDELETE

IusethetermHTTP,butHTTPSiswhatshouldbeusedeverywhere,thereforetheseexamplesuseHTTPSinsteadofHTTP.

PerformaGETRequest

consthttps=require('https')

constoptions={

hostname:'flaviocopes.com',

port:443,

path:'/todos',

method:'GET'

}

constreq=https.request(options,(res)=>{

console.log(`statusCode:${res.statusCode}`)

res.on('data',(d)=>{

process.stdout.write(d)

})

})

req.on('error',(error)=>{

console.error(error)

})

req.end()

PerformaPOSTRequest

consthttps=require('https')

constdata=JSON.stringify({

todo:'Buythemilk'

})

constoptions={

hostname:'flaviocopes.com',

port:443,

path:'/todos',

method:'POST',

headers:{

MakingHTTPrequests

132

Page 133: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

'Content-Type':'application/json',

'Content-Length':data.length

}

}

constreq=https.request(options,(res)=>{

console.log(`statusCode:${res.statusCode}`)

res.on('data',(d)=>{

process.stdout.write(d)

})

})

req.on('error',(error)=>{

console.error(error)

})

req.write(data)

req.end()

PUTandDELETEPUTandDELETErequestsusethesamePOSTrequestformat,andjustchangetheoptions.methodvalue.

MakingHTTPrequests

133

Page 134: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

AxiosAxiosisaveryconvenientJavaScriptlibrarytoperformHTTPrequestsinNode.js

IntroductionInstallationTheAxiosAPIGETrequestsAddparameterstoGETrequestsPOSTRequests

IntroductionAxiosisaverypopularJavaScriptlibraryyoucanusetoperformHTTPrequests,thatworksinbothBrowserandNode.jsplatforms.

Itsupportsallmodernbrowsers,includingsupportforIE8andhigher.

Itispromise-based,andthisletsuswriteasync/awaitcodetoperformXHRrequestsveryeasily.

UsingAxioshasquiteafewadvantagesoverthenativeFetchAPI:

Axios

134

Page 135: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

supportsolderbrowsers(Fetchneedsapolyfill)hasawaytoabortarequesthasawaytosetaresponsetimeouthasbuilt-inCSRFprotectionsupportsuploadprogressperformsautomaticJSONdatatransformationworksinNode.js

InstallationAxioscanbeinstalledusingnpm:

npminstallaxios

oryarn:

yarnaddaxios

orsimplyincludeitinyourpageusingunpkg.com:

<scriptsrc="https://unpkg.com/axios/dist/axios.min.js"></script>

TheAxiosAPIYoucanstartanHTTPrequestfromthe axiosobject:

axios({

url:'https://dog.ceo/api/breeds/list/all',

method:'get',

data:{

foo:'bar'

}

})

butforconvenience,youwillgenerallyuse

axios.get()

axios.post()

(likeinjQueryyouwoulduse $.get()and $.post()insteadof $.ajax())

AxiosoffersmethodsforalltheHTTPverbs,whicharelesspopularbutstillused:

Axios

135

Page 136: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

axios.delete()

axios.put()

axios.patch()

axios.options()

andamethodtogettheHTTPheadersofarequest,discardingthebody:

axios.head()

GETrequestsOneconvenientwaytouseAxiosistousethemodern(ES2017)async/awaitsyntax.

ThisNode.jsexamplequeriestheDogAPItoretrievealistofallthedogsbreeds,usingaxios.get(),anditcountsthem:

constaxios=require('axios')

constgetBreeds=async()=>{

try{

returnawaitaxios.get('https://dog.ceo/api/breeds/list/all')

}catch(error){

console.error(error)

}

}

constcountBreeds=async()=>{

constbreeds=awaitgetBreeds()

if(breeds.data.message){

console.log(`Got${Object.entries(breeds.data.message).length}breeds`)

}

}

countBreeds()

Ifyoudon'twanttouseasync/awaityoucanusethePromisessyntax:

constaxios=require('axios')

constgetBreeds=()=>{

try{

returnaxios.get('https://dog.ceo/api/breeds/list/all')

}catch(error){

console.error(error)

}

}

constcountBreeds=async()=>{

constbreeds=getBreeds()

Axios

136

Page 137: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

.then(response=>{

if(response.data.message){

console.log(

`Got${Object.entries(response.data.message).length}breeds`

)

}

})

.catch(error=>{

console.log(error)

})

}

countBreeds()

AddparameterstoGETrequestsAGETresponsecancontainparametersintheURL,likethis: https://site.com/?foo=bar.

WithAxiosyoucanperformthisbysimplyusingthatURL:

axios.get('https://site.com/?foo=bar')

oryoucanusea paramspropertyintheoptions:

axios.get('https://site.com/',{

params:{

foo:'bar'

}

})

POSTRequestsPerformingaPOSTrequestisjustlikedoingaGETrequest,butinsteadof axios.get,youuse axios.post:

axios.post('https://site.com/')

AnobjectcontainingthePOSTparametersisthesecondargument:

axios.post('https://site.com/',{

foo:'bar'

})

Axios

137

Page 138: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Axios

138

Page 139: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WebsocketsWebSocketsareanalternativetoHTTPcommunicationinWebApplications.Theyofferalonglived,bidirectionalcommunicationchannelbetweenclientandserver.

WebSocketsareanalternativetoHTTPcommunicationinWebApplications.

Theyofferalonglived,bidirectionalcommunicationchannelbetweenclientandserver.

Onceestablished,thechanneliskeptopen,offeringaveryfastconnectionwithlowlatencyandoverhead.

BrowsersupportforWebSocketsWebSocketsaresupportedbyallmodernbrowsers.

Websockets

139

Page 140: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HowWebSocketsdifferfromHTTPHTTPisaverydifferentprotocol,andalsoadifferentwayofcommunicate.

HTTPisarequest/responseprotocol:theserverreturnssomedatawhentheclientrequestsit.

WithWebSockets:

theservercansendamessagetotheclientwithouttheclientexplicitlyrequestingsomethingtheclientandtheservercantalktoeachothersimultaneouslyverylittledataoverheadneedstobeexchangedtosendmessages.Thismeansalowlatencycommunication.

WebSocketsaregreatforreal-timeandlong-livedcommunications.

HTTPisgreatforoccasionaldataexchangeandinteractionsinitiatedbytheclient.

HTTPismuchsimplertoimplement,whileWebSocketsrequireabitmoreoverhead.

SecuredWebSocketsAlwaysusethesecure,encryptedprotocolforWebSockets, wss://.

ws://referstotheunsafeWebSocketsversion(the http://ofWebSockets),andshouldbeavoidedforobviousreasons.

CreateanewWebSocketsconnection

consturl='wss://myserver.com/something'

constconnection=newWebSocket(url)

connectionisaWebSocketobject.

Whentheconnectionissuccessfullyestablished,the openeventisfired.

Listenforitbyassigningacallbackfunctiontothe onopenpropertyofthe connectionobject:

connection.onopen=()=>{

//...

}

Ifthere'sanyerror,the onerrorfunctioncallbackisfired:

Websockets

140

Page 141: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

connection.onerror=error=>{

console.log(`WebSocketerror:${error}`)

}

SendingdatatotheserverusingWebSocketsOncetheconnectionisopen,youcansenddatatotheserver.

Youcandosoconvenientlyinsidethe onopencallbackfunction:

connection.onopen=()=>{

connection.send('hey')

}

ReceivingdatafromtheserverusingWebSocketsListenwithacallbackfunctionon onmessage,whichiscalledwhenthe messageeventisreceived:

connection.onmessage=e=>{

console.log(e.data)

}

ImplementaWebSocketsserverinNode.jswsisapopularWebSocketslibraryforNode.js.

We'lluseittobuildaWebSocketsserver.Itcanalsobeusedtoimplementaclient,anduseWebSocketstocommunicatebetweentwobackendservices.

Easilyinstallitusing

yarninit

yarnaddws

Thecodeyouneedtowriteisverylittle:

constWebSocket=require('ws')

constwss=newWebSocket.Server({port:8080})

Websockets

141

Page 142: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

wss.on('connection',ws=>{

ws.on('message',message=>{

console.log(`Receivedmessage=>${message}`)

})

ws.send('ho!')

})

Thiscodecreatesanewserveronport8080(thedefaultportforWebSockets),andaddsacallbackfunctionwhenaconnectionisestablished,sending ho!totheclient,andloggingthemessagesitreceives.

SeealiveexampleonGlitchHereisaliveexampleofaWebSocketsserver:https://glitch.com/edit/#!/flavio-websockets-server-example

HereisaWebSocketsclientthatinteractswiththeserver:https://glitch.com/edit/#!/flavio-websockets-client-example

Websockets

142

Page 143: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

HTTPS,secureconnectionsTheHTTPSprotocolisanextensionofHTTP,theHyperTextTransferProtocol,thatprovidesecurecommunication

HTTPininsecurebydesign.

Whenyouopenyourbrowserandaskawebservertosendyouawebpage,yourdataperforms2trips:1fromthebrowsertothewebserver,and1fromthewebservertothebrowser.

Then,dependingonthecontentofthewebpage,youmighthavemoreconnectionsrequiredtogettheCSSfiles,theJavaScriptfiles,images,andsoon.

Duringanyofthoseconnections,anynetworkyourdataisgoingtocrosscanbeinspectedandmanipulated.

Theconsequencescanbeserious:youmighthaveallyournetworkactivitymonitoredandlogged,bya3rdpartyouarenotevenawareitexist,somenetworksmightinjectads,andyoumightbesubjecttoaman-in-the-middleattack,asecuritythreatwheretheattackercanmanipulateyourdataandevenimpersonateyourcomputeroverthenetwork.It'sveryeasyforsomeonetojustlistentoHTTPpacketsbeingtransmittedoverapublicandunencryptedWi-Finetwork.

HTTPSaimstosolvetheproblemattheroot:theentirecommunicationbetweenyourbrowserandthewebserverisencrypted.

Privacyandsecurityareamajorconcernintoday'sinternet.Afewyearsago,youcouldgetawaywithjustusinganencryptedconnectioninlogin-protectedpages,orduringane-commercecheckout.AlsobecauseofSSLcertificatespricingandcomplications,mostwebsitesjustusedHTTP.

TodayHTTPSisarequirementonanysite.Morethan50%ofthewholeWebusesitnow.GoogleChromerecentlystartedmarkingHTTPsitesasinsecure,justtogiveyouavalidreasontohaveHTTPSmandatory(andforced)onallyourwebsites.

WhenusingHTTPthedefaultserverportis80,andonHTTPSit's443.Itdoesnotneedtobeexplicitlyaddediftheserverusesthedefaultport,ofcourse.

HTTPSisalsosometimescalledHTTPoverSSL,orHTTPoverTLS.

Thedifferencebetweenthetwoissimple:TLSisthesuccessorofSSL.

WhenusingHTTPS,theonlythingthatisnotencryptedisthewebserverdomain,andtheserverport.

HTTPS,secureconnections

143

Page 144: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Everyotherinformation,includingtheresourcepath,headers,cookiesandqueryparametersareallencrypted.

Iwon'tgointhedetailsofanalyzinghowtheTLSprotocolworksunderthehoods,butyoumightthinkit'saddingagoodamountofoverhead,andyouwouldberight.

Anycomputationthat'saddedtotheprocessingofnetworkresourcescausesoverheadbothontheclient,theserver,andtothetransmittedpacketssize.

HoweverHTTPSenablestheuseofthenewestprotocolHTTP/2,whichhasahugeadvantageoverHTTP/1.1:itwayfaster.

Why?Therearemanyreasons,oneisheadercompression,oneisresourcemultiplexing.Oneisserverpush:theservercanpushmoreresourceswhenoneresourceisrequested.So,ifthebrowserrequestsapage,itwillalsoreceivealltheresourcesneeded(images,CSS,JS).

Detailsaside,HTTP/2isahugeimprovementoverHTTP/1.1anditrequiresHTTPS.ThismeansthatHTTPS,despitehavingtheencryptionoverhead,happenstobewayfasterthanHTTP,ifthingsareproperlyconfiguredwithamodernsetup.

HTTPS,secureconnections

144

Page 145: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

FiledescriptorsHowtointeractwithfiledescriptorsusingNode

Beforeyou'reabletointeractwithafilethatsitsinyourfilesystem,youmustgetafiledescriptor.

Afiledescriptoriswhat'sreturnedbyopeningthefileusingthe open()methodofferedbythefsmodule:

constfs=require('fs')

fs.open('/Users/flavio/test.txt','r',(err,fd)=>{

//fdisourfiledescriptor

})

Noticethe rweusedasthesecondparametertothe fs.open()call.

Thatflagmeansweopenthefileforreading.

Otherflagsyou'llcommonlyuseare

r+openthefileforreadingandwritingw+openthefileforreadingandwriting,positioningthestreamatthebeginningofthefile.Thefileiscreatedifnotexistingaopenthefileforwriting,positioningthestreamattheendofthefile.Thefileiscreatedifnotexistinga+openthefileforreadingandwriting,positioningthestreamattheendofthefile.Thefileiscreatedifnotexisting

Youcanalsoopenthefilebyusingthe fs.openSyncmethod,whichinsteadofprovidingthefiledescriptorobjectinacallback,itreturnsit:

constfs=require('fs')

try{

constfd=fs.openSync('/Users/flavio/test.txt','r')

}catch(err){

console.error(err)

}

Onceyougetthefiledescriptor,inwhateverwayyouchoose,youcanperformalltheoperationsthatrequireit,likecalling fs.open()andmanyotheroperationsthatinteractwiththefilesystem.

Filedescriptors

145

Page 146: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Filedescriptors

146

Page 147: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

FilestatsHowtogetthedetailsofafileusingNode

EveryfilecomeswithasetofdetailsthatwecaninspectusingNode.

Inparticular,usingthe stat()methodprovidedbythe fsmodule.

Youcallitpassingafilepath,andonceNodegetsthefiledetailsitwillcallthecallbackfunctionyoupass,with2parameters:anerrormessage,andthefilestats:

constfs=require('fs')

fs.stat('/Users/flavio/test.txt',(err,stats)=>{

if(err){

console.error(err)

return

}

//wehaveaccesstothefilestatsin`stats`

})

Nodeprovidesalsoasyncmethod,whichblocksthethreaduntilthefilestatsareready:

constfs=require('fs')

try{

conststats=fs.stat('/Users/flavio/test.txt')

}catch(err){

console.error(err)

}

Thefileinformationisincludedinthestatsvariable.Whatkindofinformationcanweextractusingthestats?

Alot,including:

ifthefileisadirectoryorafile,using stats.isFile()and stats.isDirectory()ifthefileisasymboliclinkusing stats.isSymbolicLink()thefilesizeinbytesusing stats.size.

Thereareotheradvancedmethods,butthebulkofwhatyou'lluseinyourday-to-dayprogrammingisthis.

constfs=require('fs')

fs.stat('/Users/flavio/test.txt',(err,stats)=>{

if(err){

console.error(err)

return

}

Filestats

147

Page 148: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

stats.isFile()//true

stats.isDirectory()//false

stats.isSymbolicLink()//false

stats.size//1024000//=1MB

})

Filestats

148

Page 149: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

FilepathsHowtointeractwithfilepathsandmanipulatetheminNode

GettinginformationoutofapathWorkingwithpaths

Everyfileinthesystemhasapath.

OnLinuxandmacOS,apathmightlooklike:

/users/flavio/file.txt

whileWindowscomputersaredifferent,andhaveastructuresuchas:

C:\users\flavio\file.txt

Youneedtopayattentionwhenusingpathsinyourapplications,asthisdifferencemustbetakenintoaccount.

Youincludethismoduleinyourfilesusing

constpath=require('path')

andyoucanstartusingitsmethods.

GettinginformationoutofapathGivenapath,youcanextractinformationoutofitusingthosemethods:

dirname:gettheparentfolderofafilebasename:getthefilenamepartextname:getthefileextension

Example:

constnotes='/users/flavio/notes.txt'

path.dirname(notes)///users/flavio

path.basename(notes)//notes.txt

path.extname(notes)//.txt

Youcangetthefilenamewithouttheextensionbyspecifyingasecondargumenttobasename:

Filepaths

149

Page 150: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

path.basename(notes,path.extname(notes))//notes

WorkingwithpathsYoucanjointwoormorepartsofapathbyusing path.join():

constname='flavio'

path.join('/','users',name,'notes.txt')//'/users/flavio/notes.txt'

Youcangettheabsolutepathcalculationofarelativepathusing path.resolve():

path.resolve('flavio.txt')//'/Users/flavio/flavio.txt'ifrunfrommyhomefolder

InthiscaseNodewillsimplyappend /flavio.txttothecurrentworkingdirectory.Ifyouspecifyasecondparameterfolder, resolvewillusethefirstasabaseforthesecond:

path.resolve('tmp','flavio.txt')//'/Users/flavio/tmp/flavio.txt'ifrunfrommyhomefold

er

Ifthefirstparameterstartswithaslash,thatmeansit'sanabsolutepath:

path.resolve('/etc','flavio.txt')//'/etc/flavio.txt'

path.normalize()isanotherusefulfunction,thatwilltryandcalculatetheactualpath,whenitcontainsrelativespecifierslike .or ..,ordoubleslashes:

path.normalize('/users/flavio/..//test.txt')///users/test.txt

Bothresolveandnormalizewillnotcheckifthepathexists.Theyjustcalculateapathbasedontheinformationtheygot.

Filepaths

150

Page 151: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ReadingfilesHowtoreadfilesusingNode

ThesimplestwaytoreadafileinNodeistousethe fs.readFile()method,passingitthefilepathandacallbackfunctionthatwillbecalledwiththefiledata(andtheerror):

constfs=require('fs')

fs.readFile('/Users/flavio/test.txt',(err,data)=>{

if(err){

console.error(err)

return

}

console.log(data)

})

Alternatively,youcanusethesynchronousversion fs.readFileSync():

constfs=require('fs')

try{

constdata=fs.readFileSync('/Users/flavio/test.txt','utf8')

console.log(data)

}catch(err){

console.error(err)

}

Thedefaultencodingisutf8,butyoucanspecifyacustomencodingusingaasecondparameter.

Both fs.readFile()and fs.readFileSync()readthefullcontentofthefileinmemorybeforereturningthedata.

Thismeansthatbigfilesaregoingtohaveamajorimpactonyourmemoryconsumptionandspeedofexecutionoftheprogram.

Inthiscase,abetteroptionistoreadthefilecontentusingstreams.

Readingfiles

151

Page 152: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WritingfilesHowtowritefilesusingNode

TheeasiestwaytowritetofilesinNode.jsistousethe fs.writeFile()API.

Example:

constfs=require('fs')

constcontent='Somecontent!'

fs.writeFile('/Users/flavio/test.txt',content,(err)=>{

if(err){

console.error(err)

return

}

//filewrittensuccessfully

})

Alternatively,youcanusethesynchronousversion fs.writeFileSync():

constfs=require('fs')

constcontent='Somecontent!'

try{

constdata=fs.writeFileSync('/Users/flavio/test.txt',content)

//filewrittensuccessfully

}catch(err){

console.error(err)

}

Bydefault,thisAPIwillreplacethecontentsofthefileifitdoesalreadyexist.

Youcanmodifythedefaultbyspecifyingaflag:

fs.writeFile('/Users/flavio/test.txt',content,{flag:'a+'},(err)=>{})

Theflagsyou'lllikelyuseare

r+openthefileforreadingandwritingw+openthefileforreadingandwriting,positioningthestreamatthebeginningofthefile.Thefileiscreatedifnotexistingaopenthefileforwriting,positioningthestreamattheendofthefile.Thefileiscreatedifnotexisting

Writingfiles

152

Page 153: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

a+openthefileforreadingandwriting,positioningthestreamattheendofthefile.Thefileiscreatedifnotexisting

(youcanfindmoreflagsathttps://nodejs.org/api/fs.html#fs_file_system_flags)

AppendtoafileAhandymethodtoappendcontenttotheendofafileis fs.appendFile()(anditsfs.appendFileSync()counterpart):

constcontent='Somecontent!'

fs.appendFile('file.log',content,(err)=>{

if(err){

console.error(err)

return

}

//done!

})

UsingstreamsAllthosemethodswritethefullcontenttothefilebeforereturningthecontrolbacktoyourprogram(intheasyncversion,thismeansexecutingthecallback)

Inthiscase,abetteroptionistowritethefilecontentusingstreams.

Writingfiles

153

Page 154: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WorkingwithfoldersHowtointeractwithfoldersusingNode

TheNode.js fscoremoduleprovidesmanyhandymethodsyoucanusetoworkwithfolders.

CheckifafolderexistsUse fs.access()tocheckifthefolderexistsandNodecanaccessitwithitspermissions.

CreateanewfolderUse fs.mkdir()or fs.mkdirSync()tocreateanewfolder.

constfs=require('fs')

constfolderName='/Users/flavio/test'

try{

if(!fs.existsSync(dir)){

fs.mkdirSync(dir)

}

}catch(err){

console.error(err)

}

ReadthecontentofadirectoryUse fs.readdir()or fs.readdirSynctoreadthecontentsofadirectory.

Thispieceofcodereadsthecontentofafolder,bothfilesandsubfolders,andreturnstheirrelativepath:

constfs=require('fs')

constpath=require('path')

constfolderPath='/Users/flavio'

fs.readdirSync(folderPath)

Youcangetthefullpath:

Workingwithfolders

154

Page 155: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

fs.readdirSync(folderPath).map(fileName=>{

returnpath.join(folderPath,fileName)

}

Youcanalsofiltertheresultstoonlyreturnthefiles,andexcludethefolders:

constisFile=fileName=>{

returnfs.lstatSync(fileName).isFile()

}

fs.readdirSync(folderPath).map(fileName=>{

returnpath.join(folderPath,fileName)).filter(isFile)

}

RenameafolderUse fs.rename()or fs.renameSync()torenamefolder.Thefirstparameteristhecurrentpath,thesecondthenewpath:

constfs=require('fs')

fs.rename('/Users/flavio','/Users/roger',(err)=>{

if(err){

console.error(err)

return

}

//done

})

fs.renameSync()isthesynchronousversion:

constfs=require('fs')

try{

fs.renameSync('/Users/flavio','/Users/roger')

}catch(err){

console.error(err)

}

RemoveafolderUse fs.rmdir()or fs.rmdirSync()toremoveafolder.

Removingafolderthathascontentcanbemorecomplicatedthanyouneed.

Workingwithfolders

155

Page 156: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

InthiscaseIrecommendinstallingthe fs-extramodule,whichisverypopularandwellmaintained,andit'sadrop-inreplacementofthe fsmodule,providingmorefeaturesontopofit.

Inthiscasethe remove()methodiswhatyouwant.

Installitusing

npminstallfs-extra

anduseitlikethis:

constfs=require('fs-extra')

constfolder='/Users/flavio'

fs.remove(folder,err=>{

console.error(err)

})

Itcanalsobeusedwithpromises:

fs.remove(folder).then(()=>{

//done

}).catch(err=>{

console.error(err)

})

orwithasync/await:

asyncfunctionremoveFolder(folder){

try{

awaitfs.remove(folder)

//done

}catch(err){

console.error(err)

}

}

constfolder='/Users/flavio'

removeFolder(folder)

Workingwithfolders

156

Page 157: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ThefsmoduleThefsmoduleofNode.jsprovidesusefulfunctionstointeractwiththefilesystem

The fsmoduleprovidesalotofveryusefulfunctionalitytoaccessandinteractwiththefilesystem.

Thereisnoneedtoinstallit.BeingpartoftheNodecore,itcanbeusedbysimplyrequiringit:

constfs=require('fs')

Onceyoudoso,youhaveaccesstoallitsmethods,whichinclude:

fs.access():checkifthefileexistsandNodecanaccessitwithitspermissionsfs.appendFile():appenddatatoafile.Ifthefiledoesnotexist,it'screatedfs.chmod():changethepermissionsofafilespecifiedbythefilenamepassed.Related:fs.lchmod(), fs.fchmod()fs.chown():changetheownerandgroupofafilespecifiedbythefilenamepassed.Related: fs.fchown(), fs.lchown()fs.close():closeafiledescriptorfs.copyFile():copiesafilefs.createReadStream():createareadablefilestreamfs.createWriteStream():createawritablefilestreamfs.link():createanewhardlinktoafilefs.mkdir():createanewfolderfs.mkdtemp():createatemporarydirectoryfs.open():setthefilemodefs.readdir():readthecontentsofadirectoryfs.readFile():readthecontentofafile.Related: fs.read()fs.readlink():readthevalueofasymboliclinkfs.realpath():resolverelativefilepathpointers( ., ..)tothefullpathfs.rename():renameafileorfolderfs.rmdir():removeafolderfs.stat():returnsthestatusofthefileidentifiedbythefilenamepassed.Related:fs.fstat(), fs.lstat()fs.symlink():createanewsymboliclinktoafilefs.truncate():truncatetothespecifiedlengththefileidentifiedbythefilenamepassed.Related: fs.ftruncate()fs.unlink():removeafileorasymboliclink

Thefsmodule

157

Page 158: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

fs.unwatchFile():stopwatchingforchangesonafilefs.utimes():changethetimestampofthefileidentifiedbythefilenamepassed.Related:fs.futimes()

fs.watchFile():startwatchingforchangesonafile.Related: fs.watch()fs.writeFile():writedatatoafile.Related: fs.write()

Onepeculiarthingaboutthe fsmoduleisthatallthemethodsareasynchronousbydefault,buttheycanalsoworksynchronouslybyappending Sync.

Forexample:

fs.rename()

fs.renameSync()

fs.write()

fs.writeSync()

Thismakesahugedifferenceinyourapplicationflow.

Node10includesexperimentalsupportforapromisebasedAPI

Forexamplelet'sexaminethe fs.rename()method.TheasynchronousAPIisusedwithacallback:

constfs=require('fs')

fs.rename('before.json','after.json',(err)=>{

if(err){

returnconsole.error(err)

}

//done

})

AsynchronousAPIcanbeusedlikethis,withatry/catchblocktohandleerrors:

constfs=require('fs')

try{

fs.renameSync('before.json','after.json')

//done

}catch(err){

console.error(err)

}

Thekeydifferencehereisthattheexecutionofyourscriptwillblockinthesecondexample,untilthefileoperationsucceeded.

Thefsmodule

158

Page 159: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Thefsmodule

159

Page 160: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ThepathmoduleThepathmoduleofNode.jsprovidesusefulfunctionstointeractwithfilepaths

The pathmoduleprovidesalotofveryusefulfunctionalitytoaccessandinteractwiththefilesystem.

Thereisnoneedtoinstallit.BeingpartoftheNodecore,itcanbeusedbysimplyrequiringit:

constpath=require('path')

Thismoduleprovides path.sepwhichprovidesthepathsegmentseparator( \onWindows,and /onLinux/macOS),and path.delimiterwhichprovidesthepathdelimiter( ;onWindows,and :onLinux/macOS).

Thesearethe pathmethods:

path.basename()

path.dirname()

path.extname()

path.isAbsolute()

path.join()

path.normalize()

path.parse()

path.relative()

path.resolve()

path.basename()

Returnthelastportionofapath.Asecondparametercanfilteroutthefileextension:

require('path').basename('/test/something')//something

require('path').basename('/test/something.txt')//something.txt

require('path').basename('/test/something.txt','.txt')//something

path.dirname()

Returnthedirectorypartofapath:

require('path').dirname('/test/something')///test

require('path').dirname('/test/something/file.txt')///test/something

Thepathmodule

160

Page 161: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

path.extname()

Returntheextensionpartofapath

require('path').dirname('/test/something')//''

require('path').dirname('/test/something/file.txt')//'.txt'

path.isAbsolute()

Returnstrueifit'sanabsolutepath

require('path').isAbsolute('/test/something')//true

require('path').isAbsolute('./test/something')//false

path.join()

Joinstwoormorepartsofapath:

constname='flavio'

require('path').join('/','users',name,'notes.txt')//'/users/flavio/notes.txt'

path.normalize()

Triestocalculatetheactualpathwhenitcontainsrelativespecifierslike .or ..,ordoubleslashes:

require('path').normalize('/users/flavio/..//test.txt')///users/test.txt

path.parse()

Parsesapathtoanobjectwiththesegmentsthatcomposeit:

root:therootdir:thefolderpathstartingfromtherootbase:thefilename+extensionname:thefilenameext:thefileextension

Example:

require('path').parse('/users/test.txt')

Thepathmodule

161

Page 162: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

resultsin

{

root:'/',

dir:'/users',

base:'test.txt',

ext:'.txt',

name:'test'

}

path.relative()

Accepts2pathsasarguments.Returnsthetherelativepathfromthefirstpathtothesecond,basedonthecurrentworkingdirectory.

Example:

require('path').relative('/Users/flavio','/Users/flavio/test.txt')//'test.txt'

require('path').relative('/Users/flavio','/Users/flavio/something/test.txt')//'something

/test.txt'

path.resolve()

Youcangettheabsolutepathcalculationofarelativepathusing path.resolve():

path.resolve('flavio.txt')//'/Users/flavio/flavio.txt'ifrunfrommyhomefolder

Byspecifyingasecondparameter, resolvewillusethefirstasabaseforthesecond:

path.resolve('tmp','flavio.txt')//'/Users/flavio/tmp/flavio.txt'ifrunfrommyhomefold

er

Ifthefirstparameterstartswithaslash,thatmeansit'sanabsolutepath:

path.resolve('/etc','flavio.txt')//'/etc/flavio.txt'

Thepathmodule

162

Page 163: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheosmoduleTheosmoduleofNode.jsprovidesusefulfunctionstointeractwithunderlyingsystem

Thismoduleprovidesmanyfunctionsthatyoucanusetoretrieveinformationfromtheunderlyingoperatingsystemandthecomputertheprogramrunson,andinteractwithit.

constos=require('os')

Thereareafewusefulpropertiesthattellussomekeythingsrelatedtohandlingfiles:

os.EOLgivesthelinedelimitersequence.It's \nonLinuxandmacOS,and \r\nonWindows.

WhenIsayLinuxandmacOSImeanPOSIXplatforms.ForsimplicityIexcludeotherlesspopularoperatingsystemsNodecanrunon.

os.constants.signalstellsusalltheconstantsrelatedtohandlingprocesssignals,likeSIGHUP,SIGKILLandsoon.

os.constants.errnosetstheconstantsforerrorreporting,likeEADDRINUSE,EOVERFLOWandmore.

Youcanreadthemallonhttps://nodejs.org/api/os.html#os_signal_constants.

Let'snowseethemainmethodsthat osprovides:

os.arch()

os.cpus()

os.endianness()

os.freemem()

os.homedir()

os.hostname()

os.loadavg()

os.networkInterfaces()

os.platform()

os.release()

os.tmpdir()

os.totalmem()

os.type()

os.uptime()

os.userInfo()

Theosmodule

163

Page 164: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

os.arch()

Returnthestringthatidentifiestheunderlyingarchitecture,like arm, x64, arm64.

os.cpus()

ReturninformationontheCPUsavailableonyoursystem.

Example:

[{model:'Intel(R)Core(TM)[email protected]',

speed:2400,

times:

{user:281685380,

nice:0,

sys:187986530,

idle:685833750,

irq:0}},

{model:'Intel(R)Core(TM)[email protected]',

speed:2400,

times:

{user:282348700,

nice:0,

sys:161800480,

idle:703509470,

irq:0}}]

os.endianness()

Return BEor LEdependingifNodewascompiledwithBigEndianorLittleEndian.

os.freemem()

Returnthenumberofbytesthatrepresentthefreememoryinthesystem.

os.homedir()

Returnthepathtothehomedirectoryofthecurrentuser.

Example:

'/Users/flavio'

Theosmodule

164

Page 165: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

os.hostname()

Returnthehostname.

os.loadavg()

Returnthecalculationmadebytheoperatingsystemontheloadaverage.

ItonlyreturnsameaningfulvalueonLinuxandmacOS.

Example:

[3.68798828125,4.00244140625,11.1181640625]

os.networkInterfaces()

Returnsthedetailsofthenetworkinterfacesavailableonyoursystem.

Example:

{lo0:

[{address:'127.0.0.1',

netmask:'255.0.0.0',

family:'IPv4',

mac:'fe:82:00:00:00:00',

internal:true},

{address:'::1',

netmask:'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',

family:'IPv6',

mac:'fe:82:00:00:00:00',

scopeid:0,

internal:true},

{address:'fe80::1',

netmask:'ffff:ffff:ffff:ffff::',

family:'IPv6',

mac:'fe:82:00:00:00:00',

scopeid:1,

internal:true}],

en1:

[{address:'fe82::9b:8282:d7e6:496e',

netmask:'ffff:ffff:ffff:ffff::',

family:'IPv6',

mac:'06:00:00:02:0e:00',

scopeid:5,

internal:false},

{address:'192.168.1.38',

netmask:'255.255.255.0',

family:'IPv4',

mac:'06:00:00:02:0e:00',

Theosmodule

165

Page 166: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

internal:false}],

utun0:

[{address:'fe80::2513:72bc:f405:61d0',

netmask:'ffff:ffff:ffff:ffff::',

family:'IPv6',

mac:'fe:80:00:20:00:00',

scopeid:8,

internal:false}]}

os.platform()

ReturntheplatformthatNodewascompiledfor:

darwin

freebsd

linux

openbsd

win32

...more

os.release()

Returnsastringthatidentifiestheoperatingsystemreleasenumber

os.tmpdir()

Returnsthepathtotheassignedtempfolder.

os.totalmem()

Returnsthenumberofbytesthatrepresentthetotalmemoryavailableinthesystem.

os.type()

Identifiestheoperatingsystem:

Linux

DarwinonmacOSWindows_NTonWindows

os.uptime()

Theosmodule

166

Page 167: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Returnsthenumberofsecondsthecomputerhasbeenrunningsinceitwaslastrebooted.

os.userInfo()

Theosmodule

167

Page 168: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheeventsmoduleTheeventsmoduleofNode.jsprovidestheEventEmitterclass

The eventsmoduleprovidesustheEventEmitterclass,whichiskeytoworkingwitheventsinNode.

Ipublishedafullarticleonthat,sohereIwilljustdescribetheAPIwithoutfurtherexamplesonhowtouseit.

constEventEmitter=require('events')

constdoor=newEventEmitter()

Theeventlistenereatsitsowndogfoodandusestheseevents:

newListenerwhenalistenerisaddedremoveListenerwhenalistenerisremoved

Here'sadetaileddescriptionofthemostusefulmethods:

emitter.addListener()

emitter.emit()

emitter.eventNames()

emitter.getMaxListeners()

emitter.listenerCount()

emitter.listeners()

emitter.off()

emitter.on()

emitter.once()

emitter.prependListener()

emitter.prependOnceListener()

emitter.removeAllListeners()

emitter.removeListener()

emitter.setMaxListeners()

emitter.addListener()

Aliasfor emitter.on().

emitter.emit()

Theeventsmodule

168

Page 169: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Emitsanevent.Itsynchronouslycallseveryeventlistenerintheordertheywereregistered.

emitter.eventNames()

ReturnanarrayofstringsthatrepresenttheeventsregisteredonthecurrentEventListener:

door.eventNames()

emitter.getMaxListeners()

GetthemaximumamountoflistenersonecanaddtoanEventListenerobject,whichdefaultsto10butcanbeincreasedorloweredbyusing setMaxListeners()

door.getMaxListeners()

emitter.listenerCount()

Getthecountoflistenersoftheeventpassedasparameter:

door.listenerCount('open')

emitter.listeners()

Getsanarrayoflistenersoftheeventpassedasparameter:

door.listeners('open')

emitter.off()

Aliasfor emitter.removeListener()addedinNode10

emitter.on()

Addsacallbackfunctionthat'scalledwhenaneventisemitted.

Usage:

door.on('open',()=>{

Theeventsmodule

169

Page 170: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

console.log('Doorwasopened')

})

emitter.once()

Addsacallbackfunctionthat'scalledwhenaneventisemittedforthefirsttimeafterregisteringthis.Thiscallbackisonlygoingtobecalledonce,neveragain.

constEventEmitter=require('events')

constee=newEventEmitter()

ee.once('my-event',()=>{

//callcallbackfunctiononce

})

emitter.prependListener()

Whenyouaddalistenerusing onor addListener,it'saddedlastinthequeueoflisteners,andcalledlast.Using prependListenerit'sadded,andcalled,beforeotherlisteners.

emitter.prependOnceListener()

Whenyouaddalistenerusing once,it'saddedlastinthequeueoflisteners,andcalledlast.Using prependOnceListenerit'sadded,andcalled,beforeotherlisteners.

emitter.removeAllListeners()

Removesalllistenersofaneventemitterobjectlisteningtoaspecificevent:

door.removeAllListeners('open')

emitter.removeListener()

Removeaspecificlistener.Youcandothisbysavingthecallbackfunctiontoavariable,whenadded,soyoucanreferenceitlater:

constdoSomething=()=>{}

door.on('open',doSomething)

door.removeListener('open',doSomething)

Theeventsmodule

170

Page 171: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

emitter.setMaxListeners()

SetsthemaximumamountoflistenersonecanaddtoanEventListenerobject,whichdefaultsto10butcanbeincreasedorlowered.

door.setMaxListeners(50)

Theeventsmodule

171

Page 172: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

ThehttpmoduleThehttpmoduleofNode.jsprovidesusefulfunctionsandclassestobuildanHTTPserver

TheHTTPcoremoduleisakeymoduletoNodenetworking.

Propertieshttp.METHODS

http.STATUS_CODES

http.globalAgent

Methodshttp.createServer()

http.request()

http.get()

Classeshttp.Agent

http.ClientRequest

http.Server

http.ServerResponse

http.IncomingMessage

Itcanbeincludedusing

consthttp=require('http')

Themoduleprovidessomepropertiesandmethods,andsomeclasses.

Properties

http.METHODS

ThispropertylistsalltheHTTPmethodssupported:

>require('http').METHODS

['ACL',

'BIND',

'CHECKOUT',

'CONNECT',

'COPY',

'DELETE',

'GET',

Thehttpmodule

172

Page 173: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

'HEAD',

'LINK',

'LOCK',

'M-SEARCH',

'MERGE',

'MKACTIVITY',

'MKCALENDAR',

'MKCOL',

'MOVE',

'NOTIFY',

'OPTIONS',

'PATCH',

'POST',

'PROPFIND',

'PROPPATCH',

'PURGE',

'PUT',

'REBIND',

'REPORT',

'SEARCH',

'SUBSCRIBE',

'TRACE',

'UNBIND',

'UNLINK',

'UNLOCK',

'UNSUBSCRIBE']

http.STATUS_CODES

ThispropertylistsalltheHTTPstatuscodesandtheirdescription:

>require('http').STATUS_CODES

{'100':'Continue',

'101':'SwitchingProtocols',

'102':'Processing',

'200':'OK',

'201':'Created',

'202':'Accepted',

'203':'Non-AuthoritativeInformation',

'204':'NoContent',

'205':'ResetContent',

'206':'PartialContent',

'207':'Multi-Status',

'208':'AlreadyReported',

'226':'IMUsed',

'300':'MultipleChoices',

'301':'MovedPermanently',

'302':'Found',

'303':'SeeOther',

'304':'NotModified',

'305':'UseProxy',

'307':'TemporaryRedirect',

'308':'PermanentRedirect',

'400':'BadRequest',

Thehttpmodule

173

Page 174: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

'401':'Unauthorized',

'402':'PaymentRequired',

'403':'Forbidden',

'404':'NotFound',

'405':'MethodNotAllowed',

'406':'NotAcceptable',

'407':'ProxyAuthenticationRequired',

'408':'RequestTimeout',

'409':'Conflict',

'410':'Gone',

'411':'LengthRequired',

'412':'PreconditionFailed',

'413':'PayloadTooLarge',

'414':'URITooLong',

'415':'UnsupportedMediaType',

'416':'RangeNotSatisfiable',

'417':'ExpectationFailed',

'418':'I\'mateapot',

'421':'MisdirectedRequest',

'422':'UnprocessableEntity',

'423':'Locked',

'424':'FailedDependency',

'425':'UnorderedCollection',

'426':'UpgradeRequired',

'428':'PreconditionRequired',

'429':'TooManyRequests',

'431':'RequestHeaderFieldsTooLarge',

'451':'UnavailableForLegalReasons',

'500':'InternalServerError',

'501':'NotImplemented',

'502':'BadGateway',

'503':'ServiceUnavailable',

'504':'GatewayTimeout',

'505':'HTTPVersionNotSupported',

'506':'VariantAlsoNegotiates',

'507':'InsufficientStorage',

'508':'LoopDetected',

'509':'BandwidthLimitExceeded',

'510':'NotExtended',

'511':'NetworkAuthenticationRequired'}

http.globalAgent

PointstotheglobalinstanceoftheAgentobject,whichisaninstanceofthe http.Agentclass.

It'susedtomanageconnectionspersistanceandreuseforHTTPclients,andit'sakeycomponentofNodeHTTPnetworking.

Moreinthe http.Agentclassdescriptionlateron.

Methods

Thehttpmodule

174

Page 175: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

http.createServer()

Returnanewinstanceofthe http.Serverclass.

Usage:

constserver=http.createServer((req,res)=>{

//handleeverysinglerequestwiththiscallback

})

http.request()

MakesanHTTPrequesttoaserver,creatinganinstanceofthe http.ClientRequestclass.

http.get()

Similarto http.request(),butautomaticallysetstheHTTPmethodtoGET,andcallsreq.end()automatically.

ClassesTheHTTPmoduleprovides5classes:

http.Agent

http.ClientRequest

http.Server

http.ServerResponse

http.IncomingMessage

http.Agent

Nodecreatesaglobalinstanceofthe http.AgentclasstomanageconnectionspersistanceandreuseforHTTPclients,akeycomponentofNodeHTTPnetworking.

Thisobjectmakessurethateveryrequestmadetoaserverisqueuedandasinglesocketisreused.

Italsomaintainsapoolofsockets.Thisiskeyforperformancereasons.

http.ClientRequest

An http.ClientRequestobjectiscreatedwhen http.request()or http.get()iscalled.

Thehttpmodule

175

Page 176: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Whenaresponseisreceived,the responseeventiscalledwiththeresponse,withanhttp.IncomingMessageinstanceasargument.

Thereturneddataofaresponsecanbereadin2ways:

youcancallthe response.read()methodinthe responseeventhandleryoucansetupaneventlistenerforthe dataevent,soyoucanlistenforthedatastreamedinto.

http.Server

Thisclassiscommonlyinstantiatedandreturnedwhencreatinganewserverusinghttp.createServer().

Onceyouhaveaserverobject,youhaveaccesstoitsmethods:

close()stopstheserverfromacceptingnewconnectionslisten()startstheHTTPserverandlistensforconnections

http.ServerResponse

Createdbyan http.Serverandpassedasthesecondparametertothe requesteventitfires.

Commonlyknownandusedincodeas res:

constserver=http.createServer((req,res)=>{

//resisanhttp.ServerResponseobject

})

Themethodyou'llalwayscallinthehandleris end(),whichclosestheresponse,themessageiscompleteandtheservercansendittotheclient.Itmustbecalledoneachresponse.

ThesemethodsareusedtointeractwithHTTPheaders:

getHeaderNames()getthelistofthenamesoftheHTTPheadersalreadysetgetHeaders()getacopyoftheHTTPheadersalreadysetsetHeader('headername',value)setsanHTTPheadervaluegetHeader('headername')getsanHTTPheaderalreadysetremoveHeader('headername')removesanHTTPheaderalreadysethasHeader('headername')returntrueiftheresponsehasthatheadersetheadersSent()returntrueiftheheadershavealreadybeensenttotheclient

Thehttpmodule

176

Page 177: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Afterprocessingtheheadersyoucansendthemtotheclientbycalling response.writeHead(),whichacceptsthestatusCodeasthefirstparameter,theoptionalstatusmessage,andtheheadersobject.

Tosenddatatotheclientintheresponsebody,youuse write().ItwillsendbuffereddatatotheHTTPresponsestream.

Iftheheaderswerenotsentyetusing response.writeHead(),itwillsendtheheadersfirst,withthestatuscodeandmessagethat'ssetintherequest,whichyoucaneditbysettingthestatusCodeand statusMessagepropertiesvalues:

response.statusCode=500

response.statusMessage='InternalServerError'

http.IncomingMessage

An http.IncomingMessageobjectiscreatedby:

http.Serverwhenlisteningtothe requesteventhttp.ClientRequestwhenlisteningtothe responseevent

Itcanbeusedtoaccesstheresponse:

statususingits statusCodeand statusMessagemethodsheadersusingits headersmethodor rawHeadersHTTPmethodusingits methodmethodHTTPversionusingthe httpVersionmethodURLusingthe urlmethodunderlyingsocketusingthe socketmethod

Thedataisaccessedusingstreams,since http.IncomingMessageimplementstheReadableStreaminterface.

Thehttpmodule

177

Page 178: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

StreamsLearnwhatstreamsarefor,whyaretheysoimportant,andhowtousethem.

WhatarestreamsWhystreamsAnexampleofastreampipe()Streams-poweredNodeAPIsDifferenttypesofstreamsHowtocreateareadablestreamHowtocreateawritablestreamHowtogetdatafromareadablestreamHowtosenddatatoawritablestreamSignalingawritablestreamthatyouendedwritingConclusion

WhatarestreamsStreamsareoneofthefundamentalconceptsthatpowerNode.jsapplications.

Theyareawaytohandlereading/writingfiles,networkcommunications,oranykindofend-to-endinformationexchangeinanefficientway.

StreamsarenotaconceptuniquetoNode.js.TheywereintroducedintheUnixoperatingsystemdecadesago,andprogramscaninteractwitheachotherpassingstreamsthroughthepipeoperator( |).

Forexample,inthetraditionalway,whenyoutelltheprogramtoreadafile,thefileisreadintomemory,fromstarttofinish,andthenyouprocessit.

Usingstreamsyoureaditpiecebypiece,processingitscontentwithoutkeepingitallinmemory.

TheNode.js streammoduleprovidesthefoundationuponwhichallstreamingAPIsarebuild.

WhystreamsStreamsbasicallyprovidetwomajoradvantagesusingotherdatahandlingmethods:

Memoryefficiency:youdon'tneedtoloadlargeamountsofdatainmemorybeforeyou

Streams

178

Page 179: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

areabletoprocessitTimeefficiency:ittakeswaylesstimetostartprocessingdataassoonasyouhaveit,ratherthanwaitingtillthewholedatapayloadisavailabletostart

AnexampleofastreamAtypicalexampleistheoneofreadingfilesfromadisk.

UsingtheNode fsmoduleyoucanreadafile,andserveitoverHTTPwhenanewconnectionisestablishedtoyourhttpserver:

consthttp=require('http')

constfs=require('fs')

constserver=http.createServer(function(req,res){

fs.readFile(__dirname+'/data.txt',(err,data)=>{

res.end(data)

})

})

server.listen(3000)

readFile()readsthefullcontentsofthefile,andinvokesthecallbackfunctionwhenit'sdone.

res.end(data)inthecallbackwillreturnthefilecontentstotheHTTPclient.

Ifthefileisbig,theoperationwilltakequiteabitoftime.Hereisthesamethingwrittenusingstreams:

consthttp=require('http')

constfs=require('fs')

constserver=http.createServer((req,res)=>{

conststream=fs.createReadStream(__dirname+'/data.txt')

stream.pipe(res)

})

server.listen(3000)

Insteadofwaitinguntilthefileisfullyread,westartstreamingittotheHTTPclientassoonaswehaveachunkofdatareadytobesent.

pipe()Theaboveexampleusestheline stream.pipe(res):the pipe()methodiscalledonthefilestream.

Streams

179

Page 180: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Whatdoesthiscodedo?Ittakesthesource,andpipesitintoadestination.

Youcallitonthesourcestream,sointhiscase,thefilestreamispipedtotheHTTPresponse.

Thereturnvalueofthe pipe()methodisthedestinationstream,whichisaveryconvenientthingthatletsuschainmultiple pipe()calls,likethis:

src.pipe(dest1).pipe(dest2)

Thisconstructisthesameasdoing

src.pipe(dest1)

dest1.pipe(dest2)

Streams-poweredNodeAPIsDuetotheiradvantages,manyNode.jscoremodulesprovidenativestreamhandlingcapabilities,mostnotably:

process.stdinreturnsastreamconnectedtostdinprocess.stdoutreturnsastreamconnectedtostdoutprocess.stderrreturnsastreamconnectedtostderrfs.createReadStream()createsareadablestreamtoafilefs.createWriteStream()createsawritablestreamtoafilenet.connect()initiatesastream-basedconnectionhttp.request()returnsaninstanceofthehttp.ClientRequestclass,whichisawritablestreamzlib.createGzip()compressdatausinggzip(acompressionalgorithm)intoastreamzlib.createGunzip()decompressagzipstream.zlib.createDeflate()compressdatausingdeflate(acompressionalgorithm)intoastreamzlib.createInflate()decompressadeflatestream

DifferenttypesofstreamsTherearefourclassesofstreams:

Readable:astreamyoucanpipefrom,butnotpipeinto(youcanreceivedata,butnotsenddatatoit).Whenyoupushdataintoareadablestream,itisbuffered,untilaconsumerstartstoreadthedata.Writable:astreamyoucanpipeinto,butnotpipefrom(youcansenddata,butnot

Streams

180

Page 181: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

receivefromit)Duplex:astreamyoucanbothpipeintoandpipefrom,basicallyacombinationofaReadableandWritablestreamTransform:aTransformstreamissimilartoaDuplex,buttheoutputisatransformofitsinput

HowtocreateareadablestreamWegettheReadablestreamfromthe streammodule,andweinitializeit

constStream=require('stream')

constreadableStream=newStream.Readable()

Nowthatthestreamisinitialized,wecansenddatatoit:

readableStream.push('hi!')

readableStream.push('ho!')

HowtocreateawritablestreamTocreateawritablestreamweextendthebase Writableobject,andweimplementits_write()method.

Firstcreateastreamobject:

constStream=require('stream')

constwritableStream=newStream.Writable()

thenimplement _write:

writableStream._write=(chunk,encoding,next)=>{

console.log(chunk.toString())

next()

}

Youcannowpipeareadablestreamin:

process.stdin.pipe(writableStream)

Howtogetdatafromareadablestream

Streams

181

Page 182: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Howdowereaddatafromareadablestream?Usingawritablestream:

constStream=require('stream')

constreadableStream=newStream.Readable()

constwritableStream=newStream.Writable()

writableStream._write=(chunk,encoding,next)=>{

console.log(chunk.toString())

next()

}

readableStream.pipe(writableStream)

readableStream.push('hi!')

readableStream.push('ho!')

Youcanalsoconsumeareadablestreamdirectly,usingthe readableevent:

readableStream.on('readable',()=>{

console.log(readableStream.read())

})

HowtosenddatatoawritablestreamUsingthestream write()method:

writableStream.write('hey!\n')

SignalingawritablestreamthatyouendedwritingUsethe end()method:

constStream=require('stream')

constreadableStream=newStream.Readable()

constwritableStream=newStream.Writable()

writableStream._write=(chunk,encoding,next)=>{

console.log(chunk.toString())

next()

}

readableStream.pipe(writableStream)

Streams

182

Page 183: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

readableStream.push('hi!')

readableStream.push('ho!')

writableStream.end()

ConclusionThisisanintroductiontostreams.Therearemuchmorecomplicatedaspectstoanalyze,andIhopetocoverthemsoon.

Streams

183

Page 184: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

WorkingwithMySQLMySQLisoneofthemostpopularrelationaldatabasesintheworld.FindouthowtomakeitworkwithNode.js

MySQLisoneofthemostpopularrelationaldatabasesintheworld.

TheNodeecosystemofcoursehasseveraldifferentpackagesthatallowyoutointerfacewithMySQL,storedata,retrievedata,andsoon.

We'lluse mysqljs/mysql,apackagethathasover12.000GitHubstarsandhasbeenaroundforyears.

InstallingtheNodemysqlpackageYouinstallitusing

npminstallmysql

InitializingtheconnectiontothedatabaseYoufirstincludethepackage:

constmysql=require('mysql')

andyoucreateaconnection:

constoptions={

user:'the_mysql_user_name',

password:'the_mysql_user_password',

database:'the_mysql_database_name'

}

constconnection=mysql.createConnection(options)

Youinitiateanewconnectionbycalling:

connection.connect(err=>{

if(err){

console.error('AnerroroccurredwhileconnectingtotheDB')

throwerr

}

})

WorkingwithMySQL

184

Page 185: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

TheconnectionoptionsIntheaboveexample,the optionsobjectcontained3options:

constoptions={

user:'the_mysql_user_name',

password:'the_mysql_user_password',

database:'the_mysql_database_name'

}

Therearemanymoreyoucanuse,including:

host,thedatabasehostname,defaultsto localhostport,theMySQLserverportnumber,defaultsto3306socketPath,usedtospecifyaunixsocketinsteadofhostandportdebug,bydefaultdisabled,canbeusedfordebuggingtrace,bydefaultenabled,printsstacktraceswhenerrorsoccurssl,usedtosetupanSSLconnectiontotheserver(outofthescopeofthistutorial)

PerformaSELECTqueryNowyouarereadytoperformanSQLqueryonthedatabase.Thequeryonceexecutedwillinvokeacallbackfunctionwhichcontainsaneventualerror,theresultsandthefields.

connection.query('SELECT*FROMtodos',(error,todos,fields)=>{

if(error){

console.error('Anerroroccurredwhileexecutingthequery')

throwerror

}

console.log(todos)

})

Youcanpassinvalueswhichwillbeautomaticallyescaped:

constid=223

connection.query('SELECT*FROMtodosWHEREid=?',[id],(error,todos,fields)=>{

if(error){

console.error('Anerroroccurredwhileexecutingthequery')

throwerror

}

console.log(todos)

})

WorkingwithMySQL

185

Page 186: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Topassmultiplevalues,justputmoreelementsinthearrayyoupassasthesecondparameter:

constid=223

constauthor='Flavio'

connection.query('SELECT*FROMtodosWHEREid=?ANDauthor=?',[id,author],(error,

todos,fields)=>{

if(error){

console.error('Anerroroccurredwhileexecutingthequery')

throwerror

}

console.log(todos)

})

PerformanINSERTqueryYoucanpassanobject

consttodo={

thing:'Buythemilk'

author:'Flavio'

}

connection.query('INSERTINTOtodosSET?',todo,(error,results,fields)=>{

if(error){

console.error('Anerroroccurredwhileexecutingthequery')

throwerror

}

})

Ifthetablehasaprimarykeywith auto_increment,thevalueofthatwillbereturnedintheresults.insertIdvalue:

consttodo={

thing:'Buythemilk'

author:'Flavio'

}

connection.query('INSERTINTOtodosSET?',todo,(error,results,fields)=>{

if(error){

console.error('Anerroroccurredwhileexecutingthequery')

throwerror

}}

constid=results.resultId

console.log(id)

)

Closetheconnection

WorkingwithMySQL

186

Page 187: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

Whenyouneedtoterminatetheconnectiontothedatabaseyoucancallthe end()method:

connection.end()

Thismakessureanypendingquerygetssent,andtheconnectionisgracefullyterminated.

WorkingwithMySQL

187

Page 188: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

DifferencebetweendevelopmentandproductionLearnhowtosetupdifferentconfigurationsforproductionanddevelopmentenvironments

Youcanhavedifferentconfigurationsforproductionanddevelopmentenvironments.

Nodeassumesit'salwaysrunninginadevelopmentenvironment.YoucansignalNode.jsthatyouarerunninginproductionbysettingthe NODE_ENV=productionenvironmentvariable.

Thisisusuallydonebyexecutingthecommand

exportNODE_ENV=production

intheshell,butit'sbettertoputitinyourshellconfigurationfile(e.g. .bash_profilewiththeBashshell)becauseotherwisethesettingdoesnotpersistincaseofasystemrestart.

Youcanalsoapplytheenvironmentvariablebyprependingittoyourapplicationinitializationcommand:

NODE_ENV=productionnodeapp.js

Thisenvironmentvariableisaconventionthatiswidelyusedinexternallibrariesaswell.

Settingtheenvironmentto productiongenerallyensuresthat

loggingiskepttoaminimum,essentiallevelmorecachinglevelstakeplacetooptimizeperformance

ForexamplePug,thetemplatinglibraryusedbyExpress,compilesindebugmodeifNODE_ENVisnotsetto production.Expressviewsarecompiledineveryrequestindevelopmentmode,whileinproductiontheyarecached.Therearemanymoreexamples.

Expressprovidesconfigurationhooksspecifictotheenvironment,whichareautomaticallycalledbasedontheNODE_ENVvariablevalue:

app.configure('development',()=>{

//...

})

app.configure('production',()=>{

//...

})

app.configure('production','staging',()=>{

//...

Differencebetweendevelopmentandproduction

188

Page 189: Table of Contents - flaviocopes.nyc3.digitaloceanspaces.com€¦ · The Node.js Handbook The Node Handbook follows the 80/20 rule: learn in 20% of the time the 80% of a topic. I find

})

Forexampleyoucanusethistosetdifferenterrorhandlersfordifferentmode:

app.configure('development',()=>{

app.use(express.errorHandler({dumpExceptions:true,showStack:true}));

})

app.configure('production',()=>{

app.use(express.errorHandler())

})

Differencebetweendevelopmentandproduction

189