nodejs brown bag
DESCRIPTION
Gabriel Falkenberg, konsult på Valtech, kommer på ett insiktsfullt och underhållande sätt berätta om lärdomar och upptäckter från sin resa med node.js. Sannolikt får vi se lite bra och/eller "intressant" kod också! "Jag försöker göra en brain dump av allt jag önskar jag hade vetat om Nodejs innan jag började."TRANSCRIPT
Intresserad av att jobba på Valtech?!Kontakta vår rekryteringskoordinator!! [email protected]!! 070-165 34 83✉☎
Gabriel Falkenberg
@gabriel_f
gabrielf
Jag heter Gabriel och jobbar här på Valtech och det senaste dryga året har jag jobbat på Viaplay med... node
Jag misstänker att det finns lite olika förväntningar på den här presentationer. * Helt nya, vill lära sig grunderna * Vet lite men vill veta mer om styrkor och svagheter * Kan en hel del men vill snappa upp lite tips och tricks
Jag hoppas att de här 45 minuterna kommer innehålla lite för alla. Fokus är det jag tycker alla som utvecklar med Node ska känna till. Jag utgår från att alla kan javascript i viss mån.
Ryan Dahl
På JSConf 2009 annonserade Ryan Dahl Node.js för första gången http://www.youtube.com/watch?v=ztspvPYybIY Han pratade om varför trådar är fel sätt att hantera samtidighet och att en event loop och asynkron I/O är ett bättre alternativ. Han bestämde sig för att se vad som hände om man lade en event loop och asynkron I/O ovanpå Javascript, kan det bli något användbart? Möt Node: Evented I/O for V8 javascript !
Samtidighet
Resten
Samtidighet = Man måste förstå hur Node fungerar vad gäller asynkron I/O och händelseloopen för att bli en bra Node-utvecklare Resten = Lättviktighet, litet & enkelt standardbibiliotek, bra pakethantering, extremt aktivt community, draghjälp av javascript i frontend
Java Node.js
Samtidighet
I en traditionell Java webbapp så serveras ett anrop av en tråd. Tråden har hand om anropet från början till slut. Det måste finnas en tråd per samtidigt anrop för att undvika att anrop hamnar på kö. !Uppenbara funderingar: * Hur är det möjligt? * Varför vill man göra så? * Varför gör inte alla så? * Vad är haken?
Web Auth
SamtidighetDBPosta blogginlägg
Returnera HTML
Mycket kan hända i webbappen under ett anrop.
Web
Java: Den nuvarande tråden väntar (andra kan jobbar vidare)
Node: Den enda tråden jobbare vidare med annat. Blir varskodd när det är möjligt att fortsätta.
Samtidighet
Skillnaden är här
Men mycket av det är väntetid. Jämför telefon vs. brev. Java ser operationerna som telefonsamtal, tråden väntar på svar Nodejs ser dem som brev och gör annat under tiden, agerar på brevet när det finns i brevlådan
15 sekunder
10ms
Så kan en tråd hinna
17 dagar
100nsLäs från RAM-minne
Läs från databas
Läs från långsamt nätverk 300ms
Datortid Människotid
Läs från L1-cache 1ns
520 dagar
0,15 sekunder
En tråd som måste vänta på I/O är ungefär lika effektiv som en utvecklare som inte får jobba medan den inväntar svar på epost eller till och med fysiska brev... !Att köra på det sättet Node gör innebär att det totala jobbet delas i många små bitar. Detta kräver ett effektivt sätt att organisera många små jobb och det är där event-loopen kommer in.
En event loopJobbkö
Det finns en kö med jobb att göra, det finns en tråd redo att göra jobbet. Jobben görs ett och ett och tråden kommer hela tiden plocka översta jobbet från kön när den är klar med det tidigare. När jobben är slut avslutas processen.
En event loopJobbkö
Det finns en kö med jobb att göra, det finns en tråd redo att göra jobbet. Jobben görs ett och ett och tråden kommer hela tiden plocka översta jobbet från kön när den är klar med det tidigare. När jobben är slut avslutas processen.
En event loopJobbkö
Det finns en kö med jobb att göra, det finns en tråd redo att göra jobbet. Jobben görs ett och ett och tråden kommer hela tiden plocka översta jobbet från kön när den är klar med det tidigare. När jobben är slut avslutas processen.
En event loopJobbkö
Det finns en kö med jobb att göra, det finns en tråd redo att göra jobbet. Jobben görs ett och ett och tråden kommer hela tiden plocka översta jobbet från kön när den är klar med det tidigare. När jobben är slut avslutas processen.
En event loopJobbkö
Men ett jobb kan också ge upphov till andra jobb. Tänk setTimeout(..., 0)
En event loopJobbkö
Men vad är ett jobb? Jo en följd synkron kod tex. den först laddade filen. Det enklaste exemplet, ett Hello, World-program, är ett jobb i den här modellen.
En event loopJobbkö
Men vad är ett jobb? Jo en följd synkron kod tex. den först laddade filen. Det enklaste exemplet, ett Hello, World-program, är ett jobb i den här modellen.
En event loopJobbkö
Men vad är ett jobb? Jo en följd synkron kod tex. den först laddade filen. Det enklaste exemplet, ett Hello, World-program, är ett jobb i den här modellen.
En event loopJobbkö
Men vad är ett jobb? Jo en följd synkron kod tex. den först laddade filen. Det enklaste exemplet, ett Hello, World-program, är ett jobb i den här modellen.
En event loopJobbkö
Här är ett lite mer avancerat exempel där tre jobb figurerar. Det första kommer att skapa två andra jobb med hjälp av setTimeout som ni säkert känner igen från javascript i webbläsaren.
En event loopJobbkö
Här är ett lite mer avancerat exempel där tre jobb figurerar. Det första kommer att skapa två andra jobb med hjälp av setTimeout som ni säkert känner igen från javascript i webbläsaren.
En event loopJobbkö
Här är ett lite mer avancerat exempel där tre jobb figurerar. Det första kommer att skapa två andra jobb med hjälp av setTimeout som ni säkert känner igen från javascript i webbläsaren.
En event loopJobbkö
Här är ett lite mer avancerat exempel där tre jobb figurerar. Det första kommer att skapa två andra jobb med hjälp av setTimeout som ni säkert känner igen från javascript i webbläsaren.
En event loopJobbkö
Här är ett lite mer avancerat exempel där tre jobb figurerar. Det första kommer att skapa två andra jobb med hjälp av setTimeout som ni säkert känner igen från javascript i webbläsaren.
En event loopJobbkö
Men ett jobb kan också ge upphov till andra jobb. Tänk setTimeout(..., 0)
En event loopJobbkö
Men ett jobb kan också ge upphov till andra jobb. Tänk setTimeout(..., 0)
En event loopJobbkö
Men ett jobb kan också ge upphov till andra jobb. Tänk setTimeout(..., 0)
En event loopJobbkö
Men ett jobb kan också ge upphov till andra jobb. Tänk setTimeout(..., 0)
En event loopJobbkö
Men det är förstås inte så här enkelt. Det finns också asynkrona operationer som inte direkt kan läggas till kön utan kan utföras först i framtiden. Vi kan säga att det är jobb som schemalagts.
En event loopJobbköSchemaläggare
Men det är förstås inte så här enkelt. Det finns också asynkrona operationer som inte direkt kan läggas till kön utan kan utföras först i framtiden. Vi kan säga att det är jobb som schemalagts.
En event loopJobbköSchemaläggare
Så när ett jobb körs så kan det inte bara hamna nya jobb på kön utan de kan också schemaläggas på lite olika sätt.
En event loopJobbköSchemaläggare
Så när ett jobb körs så kan det inte bara hamna nya jobb på kön utan de kan också schemaläggas på lite olika sätt.
En event loopJobbköSchemaläggare
Jobb som läggs på kön efter en viss tid, setTimeout(..., 100) Jobb som läggs på kön när en asynkron I/O operation är klar Och jobb som läggs på kön när något händer på nätverket
En event loopJobbköSchemaläggare
Jobb som läggs på kön efter en viss tid, setTimeout(..., 100) Jobb som läggs på kön när en asynkron I/O operation är klar Och jobb som läggs på kön när något händer på nätverket
En event loopJobbköSchemaläggare
Jobb som läggs på kön efter en viss tid, setTimeout(..., 100) Jobb som läggs på kön när en asynkron I/O operation är klar Och jobb som läggs på kön när något händer på nätverket
En event loopJobbköSchemaläggare
Jobb som läggs på kön efter en viss tid, setTimeout(..., 100) Jobb som läggs på kön när en asynkron I/O operation är klar Och jobb som läggs på kön när något händer på nätverket
En event loopJobbköSchemaläggare
Undertiden vår tråd väntar på de här jobben så finns de inte på kön men de kan hindra processen från att avslutas
En event loopJobbköSchemaläggare
När tiden har gått så läggs jobbet på kön När filen lästs från disk så läggs jobbet på kön
En event loopJobbköSchemaläggare
När tiden har gått så läggs jobbet på kön När filen lästs från disk så läggs jobbet på kön
En event loopJobbköSchemaläggare
När tiden har gått så läggs jobbet på kön När filen lästs från disk så läggs jobbet på kön
En event loopJobbköSchemaläggare
En öppen socket däremot kan ge upphov till en hel drös med jobb En extremt viktig aspekt av hur node fungerar är att ett jobb inte avbryts utifrån. Du kontrollerar när tråden kommer tillbaka till kön. Tänk kooperativ multikörning istället för preemptive. Du kan stöka till så mycket du vill så länge du städar efter dig. Farligt med Exceptions! Stäng av processen kontrollerat efter varje...
En event loopJobbköSchemaläggare
En öppen socket däremot kan ge upphov till en hel drös med jobb En extremt viktig aspekt av hur node fungerar är att ett jobb inte avbryts utifrån. Du kontrollerar när tråden kommer tillbaka till kön. Tänk kooperativ multikörning istället för preemptive. Du kan stöka till så mycket du vill så länge du städar efter dig. Farligt med Exceptions! Stäng av processen kontrollerat efter varje...
! Mindre minnesanvändning per anrop
! Enklare kod pga ingen multitrådning
! Inga lås leder till bra prestanda
! Bara ett sätt att skala
Fördelar och nackdelar med att jobba i en entrådad miljö. * Minnesanvändning är kanske inte ett problem för en vanlig webbserver kan blir det för websockets * Multitrådad programmering kan vara svårt: lås, deadlocks osv. * Kan vara långsamt att context-switcha mellan trådar, vänta på lås * Skala med processer istället för trådar och processer
# Passar inte CPU-bundna problem
" Callback hell
* Callback hell. Att utveckla asynkront gör koden så komplicerad/ful att den är svår att hantera. * Asynkrona, händelsestyrda system liknar på sätt och vis ko-operativ multitasking, om ett varv i händelseloopen tar för lång tid får alla händelser på kö lida. while (true) {} hänger hela processen.
$% Inge kul att hantera request-state
# Passar inte CPU-bundna problem
" Callback hell
* En tråd per anrop gör det enkelt att hantera request-state med thread-local storage. * Men! Continuation-local storage är en magisk modul som kan lösa det. Det används bland annat av new relics node plugin.
Continuation-Local Storage$
# Passar inte CPU-bundna problem
" Callback hell
* En tråd per anrop gör det enkelt att hantera request-state med thread-local storage. * Men! Continuation-local storage är en magisk modul som kan lösa det. Det används bland annat av new relics node plugin.
Continuation-Local Storage$
# Passar inte CPU-bundna problem
" Callback hell
* Det finns många webbramverk med asynkron I/O idag. Node är inte unikt och inte snabbare än andra språk! * I Nodejs är dock hela standardbiblioteket asynkront från start. Ryan valde Javascript då språket var anpassat för en tråd, men saknade standardbibliotek. * Googla på “read file java” och “read file node” och se skillnaden. * Det är svårare att göra fel av misstag
Continuation-Local Storage$
# Passar inte CPU-bundna problem
Meh! Andra asynkrona
ramverk då?
" Callback hell
* Det finns många webbramverk med asynkron I/O idag. Node är inte unikt och inte snabbare än andra språk! * I Nodejs är dock hela standardbiblioteket asynkront från start. Ryan valde Javascript då språket var anpassat för en tråd, men saknade standardbibliotek. * Googla på “read file java” och “read file node” och se skillnaden. * Det är svårare att göra fel av misstag
Exempel på ett litet node-program. Intressanta saker är: console.log och setTimeout är inte en del av javascript utan liknar motsvarande funktioner i webbläsaren av bekvämlighet Processen stängs inte ner förrän setTimeout är klart. Men inte så kul om man inte kan inkludera funktionalitet från andra filer/moduler
#!/usr/bin/env node
Kör med "node fil.js" eller med en shebang och ./fil.js
Node implementerar CommonJS som är en spec för beroendehantering i javascript där saker inkluderas med require. Relativa eller absolute sökvägar för dina egna filer require är synkron! Cirkulära beroenden hanteras men med vissa begränsningar
Även json-filer kan inkluderas
Skriver du ingen filändelse inkludera i förstahand en js-fil och i andra hand en json-fil
Inkluderar du en mapp kommer node leta efter en modul-beskrivning (package.json) och inkludera modulen huvud-fil och i andra hand index.js och tredje hand index.json
Externa moduler inkluderas som ett enkelt namn och node kommer då att leta i ./node_modules och uppåt i trädet såvida det inte rör sig om en core-modul som har företräde !Men vad är det som jag importerar?
Jo du importerar det som den andra filen/modulen exporterar i module.exports. module.exports är från början ett tomt objekt men här exporteras istället en sträng.
Men du kan förstås exportera annat som funktioner eller objekt.
Eller en klass. !Om exemplet kom från en enda fil skulle bara klassen exporteras eftersom det är vad module.exports innehåller till slut.
Bara det i module.exports blir synligt. Inte det som i webbläsaren skulle vara globala variabler!
Förutom om du glömmer var...
Förändringar du gör av globala klasser syns överallt, var försiktig! !Det var en väldigt snabb introduktion till hur node-kod kan se ut. Läs dokumentationen.
Dokumentation finns på http://nodejs.org/api och är föredömligt kort eftersom standardbiblioteket är så minimalt. Det tar troligtvis kortare tid att läsa genom all dokumentation här än att scrolla igenom all dokumentation om Javas standardbibliotek... Istället för ett enormt standardbibliotek finns...
npm står för node package manager och är ett väldigt trevligt verktyg för allt möjligt som rör ett node-projekt. Allt från installera beroenden till att köra olika typer av test och bygg-script.
{! "name": "my-lib",! "version": "0.0.0",! "main": "index.js",! "scripts": {! "test": "mocha"! },! "dependencies": {…}!}
Semantic Versioning
X.Y.ZMajor Minor Patch
main pekar ut den fil som exporteras från biblioteket eller som används för att starta applikationen. Versioner behandlas enligt semantik versioning semver.org Major = ej bakåtkompatibla ändringar, Minor = bakåtkompatibla tillägg, Patch = bakåtkompatibla buggfixar. Dock specialbehandlas versioner som börjar med 0, se npmjs.org/doc/misc/semver.html
"dependencies": {! "async": "0.2.10",! "lodash": "^2.0.0",! "colors": "~0.6.0",!}
beroenden anges med version och kan vara exakta, kompatibla (enligt semver) eller ganska lika (patch-siffran kan öka). Använd kompatibel version (^) om du inte verkligen har anledning att tro att modulens förvaltare inte följer semver.
npm init!npm install pkg [--save]!npm install pkg [--save-dev]!npm uninstall pkg [--save]!npm prune!npm ls
init: Skapa nytt projekt install: Installera beroende i node_modules, spara till package.json kan ange version med @version prune: Ta bort ur node_modules ls: Lista beroenden !
npm test!npm run package-json-script!npm link!npm link pkg
test: Kör scripts.test från package.json run: Kör annat script definerat i package.json link: Skapa symlänkar till moduler under utveckling av diton
npm shrinkwrap [--dev]
1.0.0^2.1.0 ?
npm hanterar beroenden transitivt. Ett beroende med ett versionsspann kan leda till olika versioner lokalt och i produktion när en ny version av beroendet släpps. Det ska fungera enligt semver men tänk på det finns problem i den nya versionen? Lösningen är npm shrinkwrap som tyvärr är förknippad med massa buggar... Du kan tex. inte styra längre om dev-beroenden ska installeras. Se github för issues.
npm version patch!npm outdated!npm update pkg
version: Stega upp din moduls version, gör en git-commit/tag etc. outdated/update: Upptäck och öka versionen på dina beroenden Tips: Spana in modulers beroenden och moduler som personer du ser upp till skapar samt deras beroenden. Det är ett perfekt sätt att lära sig om nya moduler!
Lägg!./node_modules/.bin/!
! i din PATH!
npm-moduler installeras som standard lokalt. Vissa moduler (grunt-cli, mocha) vill bli installerade globalt men gör inte det! Lägg istället ./node_modules/.bin/ i din PATH så slipper du eventuella versionskonflikter mellan dina Node-projekt.
// package.json!!
"scripts": {! "test": "mocha && jshint",! "build": "grunt"!}
./node_modules/.bin/ finns redan i PATH för scripts. mocha, jshint och grunt ovan kommer i första hand köras från de lokalt installerade modulerna.
Jag fick frågan en gång om det går att programmera Javascript utan att bli galen just med tanke på alla callbacks. !Innan vi går igenom strategier för att hantera callback-hell så ska vi dissekera en callback lite.
Anatomin av en callback-funktion
Ett callback är en funktion som skickas till en annan funktion och anropas när den andra funktionen är klar, antingen på grund av fel eller eftersom den är färdig. För idiomatiska callbacks i node gäller: * Callbacken skickas sist i parameterlistan * Den kallas antingen med ett fel eller data eller inget, inte både och * Det kallas antingen synkront eller asynkront, aldrig en blandning
Anatomin av en callback-funktion
forEach är ett exempel på kod som alltid körs synkront dvs. i exemplet ovan kommer utskriften bli: > före > i callback 1..3 > efter
Anatomin av en callback-funktion
setTimeout kommer lägga callbacken på jobbkön så den körs som snabbast nästa varv genom händelseloopen (kanske ännu längre fram i tiden beroende på last) utskriften blir: > före > efter > i callback
Möt callback hell
Det här är ett enkelt exempel, ett verkligt exempel skulle inte få plats på en sida. Men man ser den klassiska pyramid-formen även kallad "pyramid of doom". !Så hur hanterar man callback hell?
Hantera callback hell
Diciplin + bibliotek
ES6 generators
Promises
Hantera callback hell
Diciplin + bibliotek
Men man bör förstå första klassens funktioner, hur funktioner kan skapa andra funktioner, hur de kan skickas runt, hur de kan manipuleras med bind, hur de kan köras med call och apply. Vissa tycker sådana konstruktioner är för mycket magi men se till att alla utvecklare lär sig de här verktygen så kan koden bli mycket snyggare.
Hantera callback hell
ES6 generators
ES6 = EcmaScript 6 = nästa version av Javascript. Aktivera när du kör "node --harmony fil.js". Just generatorer fungerar bara med Node 0.11 och högre.
Hantera callback hell
Promises
Vanlig promiseskod. Dock inte alls optimal som jag fått lära mig av Jakob Mattson som skrivit ett promises-ramverk som heter z-core: https://github.com/jakobmattsson/z-core
Hantera callback hell
Promises
Se: https://speakerdeck.com/jakobmattsson/how-to-star-actually-star-use-promises-in-javascript
Vanliga fel
Vanliga fel
Två fel, ingen return efter callback (absolut vanligaste felet!). Välj en kodstil som du tycker minskar risken att callbacken anropas två gånger !Ingen try/catch runt JSON.parse (nästan enda metoden i standardbiblioteket som kastar undantag, var uppmärksam!)
Vanliga fel
Problem i try/catch. Om callback, som anropas synkront, kastar fel så fångas det här.
Vanliga fel
Rätt kod, men ful. Du vill kanske extrahera JSON-parsning till en asynkron funktion som innehåller det fula try/catch-blocket.
Vanliga fel
Här har vi förenklat fel-callbacken och vi använder oss av smidig js-syntax men det är fortfarande ett problem i koden. Om data finns i cachen så anropas callbacken synkront istället för asynkront. Gör inte det! Ändrar kör-ordningen i den kallande koden.
Vanliga fel
Skillnaden här är hur callbacken anropas. Det finns tre sätt att schemalägga anrop av funktioner: setTimeout(..., 0), process.nextTick(...), setImmediate(...) Läs på om dessa! Om du inte orkar, använd alltid setImmediate.
Vanliga fel
Node innehåller en extremt användbar interaktiv prompt. Men var försiktig om du använder lodash eller underscore eftersom "_" i prompten används för värdet av senaste uttrycket.
Vanliga fel
Efter ett tag så skriver man callback-koden automatiskt och då kan det blir såhär. Koden i callbacken tillför i princip ingenting. Den kan förenklas till...
Vanliga fel
...den här. Men tänk på att det bara gäller idiomatisk node-kod dvs. när man INTE får BÅDE err och data. I den här formen är det enkelt att se att callbacken inte tillför något alls och den kan tas bort...
Vanliga fel
Och bli som exemplet ovan. Här är det uppenbart att doStuff inte tillför något heller...
& Mellanhand, mycket I/O och väntan
% Problem där CPUn är flaskhalsen
' Många samtidiga anrop (websockets)
( Om du hatar Javascript
The end
Bilder från!http://www.wpzoom.com!https://www.costumania.com/