nodejs brown bag

Post on 01-Nov-2014

1.115 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

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!! anna.engman@valtech.se!! 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/

top related