Přejít k navigační liště

Zdroják » JavaScript » JavaScript na serveru: Začínáme s Node.js

JavaScript na serveru: Začínáme s Node.js

Články JavaScript, Různé

Máloco vyvolalo ve světě webových technologií poslední dobou stejnou vřavu jako serverový framework Node.js. Někomu se zdá samotná myšlenka použití JavaScriptu na serveru špatná, ale pokud k takovým lidem nepatříte a zajímá vás, proč způsobil Node.js takový zájem, naleznete odpověď v následujícím seriálu.

Node.js je vysoce výkonné, událostmi řízené prostředí pro Javascript. Už jsme o něm na Zdrojáku dříve psali, ale i tak jistě dokáže tato první věta rozpoutat v komentářích pod článkem peklo. Nuže – komentujte, my ale pokračujeme dál.

Základem Node.js je javascriptový interpret V8 z Google Chrome. Nad ním je tenká vrstva kódu v C++ poskytující minimální nutné zázemí (event-loop vyhodnocující příchozí události, obsluha I/O bufferů a jiné).

Nic z toho ale není momentálně pro nás důležité – Node se snaží být navržen tak, aby tyto nízkoúrovňové problémy vyřešil správně za vás. Některými detaily/vnitřnostmi se budeme zabývat v dalších článcích. Prozatím postačí vědět, že uživatelské rozhraní pro Node je čistý JavaScript v jediném vlákně – a v 99 % případů vše magicky funguje VELMI rychle a škálovatelně.

Článek je prvním ze série, kterou zde na Zdrojáku chystáme. V navazujících článcích se postupně podíváme na stavbu aplikace z modulů (CommonJS), postavíme si v rychlosti pár web aplikací (pomocí Connect a Express), řešení pro streamování a real-time komunikaci (Socket.IO) a dojde i na deployment na produkční prostředí. Při tom všem ovšem musíme používat instalaci Node včetně podpory pro debugování, balíčkovacího systému a jiných nástrojů. V dnešním článku společně projdeme instalaci, abychom jí porozuměli a měli společnou základnu. Pokud nemáte moc času, můžete pro hraní/experimenty použít už připravenou image virtuálního serveru, viz návod na konci článku. A tady je v kostce to, o co přijdete:

  • nainstalujeme Node včetně debug podpory;
  • Node má novou nestabilní verzi 0.3, my ale zůstaneme u 0.2.x z důvodu kompatibility;
  • poté nainstalujeme balíčkovací systém pro Node – NPM (node package manager);
  • na závěr nainstalujeme debugger node-inspector
  • a poté si ještě zkusíme odladit jednoduchý program

Níže popisované příklady budou platné pro Linux/UNIX/OS X. Pokud máte Windows, budu od vás očekávat trochu vlastní iniciativy – tedy rozchodit obdobu UNIXových příkladů v Cygwin prostředí. Další dobrá alternativa k experimentování je už je virtuální server od VirtualMasteru, viz konec článku.

Instalace Node

Instalaci provedeme kompilací ze zdrojových kódů, ale nebojte se, Node má málo dependencí a kompiluje se snadno. V nedávné době vyšla nová verze 0.3, nicméně jedná se zatím o nestabilní větev s podstatnými změnami v API. Proto budeme používat poslední stabilní verzi z 0.2 větve. Stáhněte si příslušný zdrojový kód, rozbalte a nainstalujte nějak takto:

$ tar xzf node-v0.2.5.tar.gz
$ cd node-v0.2.5
$ ./configure --debug # důležité, zde je nastavení pro podporu ladění
$ make
$ sudo make install # pokud instalujete do /usr/local, budete (zatím) potřebovat root práva 

Instalace NPM

Hned druhý krok bude instalace balíčkovacího systému npm, což je taková Node varianta rubygems. Umožní vám jednoduše prohlížet a instalovat Node programy a knihovny, včetně závislostí. Je dobré zmínit, že npm má poněkud agresivní zásady vynucování bezpečnosti a bude vás VELMI otravovat, pokud ho nainstalujete a budete používat pod root uživatelem. Nedoporučuji. Naopak defaultní instalace směřuje do /usr/local (který obvykle root práva vyžaduje) a autor je toho názoru, že je vhodné /usr/local prostě změnit vlastníka. S trochou skřípění zubů, ale budiž:

$ whoami
node # not root!
$ sudo chown -R $USER /usr/local
$ curl http://npmjs.org/install.sh | sh 

Instalace debuggeru

Jakmile se zanoříte po uši do nového jazyka nebo prostředí, přijdou problémy. Přijdou zaručeně, možná by šlo si podle nich i řídit hodinky, protože vaše kroky v Node krajině budou lemovány zleva i zprava kódem alfa-kvality. Proto je dobré začít od píky tím, že si hned na začátku rozchodíme prostředí pro ladění.

Ačkoliv je Node prostředí mladé, máte překvapivě hned několik možností, např. integrovaný debugger v Eclipse či command-line debugger. Autor článku za vás ale autoritativně vybral interaktivní debugger založený na JS debuggeru ve Webkit Inspectoru (debuggeru v Chrome a Safari). Poprvé si na něm taky v praxi ukážeme, jak nainstalovat npm modul (nezapomeňte změnit vlastníka /usr/local a vnořených složek pro aktuálního usera):

$ npm install node-inspector
...
npm ERR! node-inspector@0.1.0 not compatible with your version of node
npm ERR! Requires: node@>=0.3.0
npm ERR! You have: node@v0.2.4
npm not ok 

No – to se příliš nepovedlo. Hned v praxi tedy vidíte, jaké problémy může přinášet dynamicky se vyvíjející platforma. Nejnovější verze node-inspector pracuje pouze s Node >= 0.3 – s níž ovšem zase nefunguje spousta jiných knihoven, které budeme používat, a proto jsme nainstalovali z důvodů kompatibility nejnovější stable branch 0.2.4. (Samozřejmě jsem si to mohl odpustit, nicméně na podobné problémy asi narazíte za chvíli sami, je dobré si s nimi umět poradit. – pozn.aut.) Inu, nezbývá než vyzkoušet předchozí verzi:

$ npm ls | grep node-inspector
node-inspector@0.0.1      =dannycoates remote
node-inspector@0.0.2      =dannycoates remote
node-inspector@0.0.3      =dannycoates remote
node-inspector@0.0.4      =dannycoates remote
node-inspector@0.1.0      =dannycoates latest remote
$ npm install node-inspector@0.0.4
...
npm info build Success: node-inspector@0.0.4
npm ok 

To už je lepší. Pokud všechno půjde dobře, měl by vám nyní v příkazové řádce fungovat příkaz node-inspector (zatím ale neudělá nic).

Jen v rychlosti si načrtneme, jak řešení funguje: protože jsme Node společnými silami na začátku nakonfigurovali před kompilací pro podporu ladění, akceptuje nyní node příkaz parametr —debug. Pokud se takto pustí, Node předává informace na lokálním portu. node-inspector potom nad tímto základním rozhraním provozuje výše zmíněný debugger WebKitu a informace mezi ním a Node procesem překládá.

Výsledek je sympatický – můžete debugovat ve stejném prostředí jak svůj serverový kód, tak svůj klientský kód. Navíc můžete debugovat kód přes internet na jiném počítači, dokonce můžete debugovat z víc míst najednou. Je to tedy takový MMODBG – Massively Multiplayer Online Debugger.

Pozdrav slušně!

Nastal onen klíčový moment, kdy zkusíme pozdravit svět! Abych vám to usnadnil, připravil jsem ukázkový program už s chybou, takže si trochu zaladíme. Pokud jste tak ještě neučinili, pusťte node-inspector na pozadí (ukončit ho později můžete příkazem  killall node-inspector):

$ node-inspector & 

A dále si zkopírujte/uložte do souboru hello-world.js následující kód:

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  req.end('Hello Worldn');
}).listen(8124);
console.log('Server running at http://localhost:8124/');

Tohle je základní a mnohokrát omílaný příklad HTTP serveru, který na každý požadavek vrací “Hello World”. Ale tenhle je drobně pozměněn, takže nefunguje. Spusťte příklad debug příkazem:

$ node --debug hello-world.js
debugger listening on port 5858
Server running at http://localhost:8124/ 

Nejprve Node zahlásí, že debugovací informace jsou dostupné na portu 5858, a poté hello-world.js (řádka 6) zahlásí že byl spuštěn HTTP server na portu 8124. Zkuste se nyní tedy připojit na http://localhost:8124/

/Users/jakub/Sites/node/hello-world.js:4
  req.end('Hello Worldn');
      ^
TypeError: Object #<an IncomingMessage> has no method 'end'
    at Server.<anonymous> (/Users/jakub/Sites/node/hello-world.js:4:7)
    at Server.emit (events:27:15)
    at HTTPParser.onIncoming (http:831:10)
    at HTTPParser.onHeadersComplete (http:87:31)
    at Stream.ondata (http:763:22)
    at IOWatcher.callback (net:494:29)
    at node.js:773:9
$ 

Ouha. Jak vidíte, aplikace zahlásila výjimku a spadla. Ze stacktrace je vidět, že na řádce 4 tvrdí, že objekt req nemá metodu end. Pusťte tedy pokusný skript ještě jednou ( node --debug hello-world.js) a pojďme se podívat, co se na místě děje. Otevřete v prohlížeči tentokrát node-inspector na http://localhost:8080/. Po připojení bude potřeba přepnout se do správného souboru (Node jich naimportuje na základně závislostí více – ale o tom si povíme v příštím díle) – viz obrázek:

Kliknutím vlevo od řádky 3 umístěte breakpoint. Nyní se běh programu přeruší automaticky na této řádce. Aby program do tohoto callbacku vstoupil, otevřete si v druhém okně prohlížeče znovu na aplikaci, kterou ladíme – na portu 8124. Tentokrát, jak vidíte, prohlížeč odpověď nedostane a jen se točí – aplikace totiž v druhém okně čeká na našem breakpointu:

Nebudeme tedy v tomto jednoduchém a trochu umělém příkladu dále chodit kolem horké kaše – překlep je na další řádce, ukončit je samozřejmě potřeba výstupní proud v proměnné res (response), nikoliv vstup req (request). Stačí dvakrát poklepat na zmíněnou řádku a můžete kód přímo naživo upravovat – přepište tedy q na s a kliknutím na jinou řádku změny uložíte. Nyní můžete program dál pustit (v pravém horním rohu).

To by bylo pro dnešek všechno. Pokud se v průběhu návodu někde zaseknete, neváhejte napsat do komentářů pod článkem o pomoc. V příštím díle seriálu se podíváme na způsob, jakým do své aplikace naimportujeme knihovny a cizí kód (CommonJS Modules) a představíme si několik jednoduchých knihoven pro rychlou tvorbu web aplikací (Connect a Express).


Hrajeme si v oblacích

Pokud nemáte čas či energii celou instalací projít, ale přesto byste chtěli zkusit začít experimentovat s Node, mám tu pro vás speciální nabídku. Připravil jsem pro vás virtuální obraz disku, se založeným non-root uživatelem, s nainstalovaným node a npm a node-inspector. Pokud se opravdu chcete připravit o potěšení vše nainstalovat sami, zde je rychlý způsob jak do experimentování naskočit. A bude vás to stát bratru zhruba korunu na den!

Upozornění: přes veškerou snahu se autorovi zatím nedaří obejít chybu v implementaci debuggeru pod Ubuntu. Kapitoly o ladění pomocí debuggeru bude potřeba zatím přeskočit. Pokud problém bude vyřešen, upravím šablonu a upozorním na ni v dalším článku.

  • založte si účet u VirtualMaster.cz
  • otevřete si Zdroják node.js šablonu serveru a vytvořte nový server
  • přihlaste se ssh node@<ip-adresa> (ip adresa přijde mailem), heslo k tomuto uživateli je  changeit
  • po přihlášení toto heslo změňte (příkazem passwd) na něco více osobního
  • pokud chcete, přidejte svůj veřejný klíč do ~/.ssh/authorized_keys

Komentáře

Subscribe
Upozornit na
guest
23 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Martin Soušek

Tak zatím jsem odpověď na otázku „proč způsobil node.js takový zájem“ nedostal. Tak snad příště.

Neboli – má cenu se učit nový framework?

Ale uznávám, že aplikace http://nodeknockout.com/ nebo http://expressjs.com/applications.html jsou hezké.

Jakub

Trochu jsem očekával, že tuhle otázku už si čtenář zodpověděl sám dříve, nad některým z úvodních článků o node.js.

Podle mne je hlavním důvodem, že činí tradičně složité programování asynchronních serverů a proudového zpracování směšně jednoduchým. Jsou další důvody – např. jeden jazyk na serveru i klientovi, či vysoká rychlost node.js při zachování nízké složitosti atp…

Tomáš Witek

Někde na netu jsem se dočetl, že vyvojáři si stále neuvědomují hlavní výhodu node.js a právě proto vznikají frameworky jako Connect či Express, které většinou pouze kopírují již zavedenou technologii jako je např. RoR či Sinatra a nevyužijí tím hlavní potencionál node.js.

Viz. video: http://jdem.cz/hykg8

Souhlasíte s tímto názorem?
Můžete v dalším článku zabrousit do tohoto problému, nebo alespoň odkázat na článek, který tohle řeší?

Node.js potenciál

Ano, převážně souhlasím. Node.js těží z Javascriptu, což je jazyk zajímavý, velmi silný a pěkný, ale dost atypický a způsoby, jak ho elegantně používat, se stále vyvíjejí.

Kopírovat Ruby svět (RoR, Sinatra) je přirozená první vlna vývoje – obě komunity jsou zaměřené na eleganci, jednoduchost a rychlost vývoje atd.

Nicméně všichni tak nějak cítí, že je potřeba najít nové paradigma. Ve světe client-side Javascriptu to byl jQuery, který si jako první uvědomil jednoduchost a expresivitu CSS selektorů a postupu „vyber DOM elementy a pak na ně aplikuj změny“.

Je to otevřené téma, které je stále živé. Není na něj zatím definitivní odpověď (ve formě nového přístupu). Nicméně díky za podnět, v příštím díle (který bude primárně o Connect/Expressu) se o tom zmíním a naznačím i jiné, další možnosti.

Tomáš

Osobně v node.js nevidím potenciál.

Je tam spousta technologických problémů, které jsou dost spjaty s použitím interpretrem – V8. např. to, že je to single-threaded, což způsobí problém když GC začne uklízet. Jelikož zastaví hlavní thread a aplikace čeká. To způsobí, že odpověď se opozdí o několik stovek milisekund. Tohle to není vůbec problém v prohlížeči, ale na serveru je to celkem velký problém.

Nevyužívá ani dnes populární více jádrové procesory. Kvůli tomu, že je singe-threaded. Je sice možnost ho pustit tolikrát kolik má počítač jader a dát před to balancer, ale je to prostě další problém, který člověk musí řešit, tak obskurně.

Ať se snaží optimalizovat V8 jak chtějí stále to není nic moc v porovnání o ostatními jazyky. Je to stále dynamický jazyk a i když tam je JIT, takže výhoda proti ostatnímu jazykům v podstatě není.

Sám jazyk JavaScript. Má sice spoustu výhod a je v něm spoustu chytrých myšlenek, ale na druhou stranu je tam spousta věcích vyloženě nedomyšlených a způsobují dost problémy. Existuje sice hromada hacků jak tyto problémy obejít, ale kdo chce pořád programovat s hacky, aby mohl řešit problémy, které v ostatních jazycích nejsou?

např. globální kontext. Neexistují jmenný prostory ani moduly. Tohle sice řeší CommonJS, který představuje jakési jmenné prostory, ale osobně jejich implementaci nevidím moc šťastně. Komu se libí psát export. před vším co chce dát ven a pak když něco require tak tomu musí dávat jméno. Nemožnost mít dva soubory ve stejném prostoru apod.

Myšlenka asynchronního programování je super, ale node.js není řešení. Jelikož velký výhoda asynchronního programování je u serveru, kde je vyžadováno spousta spojení, což je třeba Comet server. Bohužel node.js jako Comet server je zcela nevhodný kvůli V8, která bude brzdit spojení kvůli GC. Napsal o tom např. autor sociální sítě Plurk, kde použili node.js a bylo to zcela nevhodné řešení, které nakonec přepsali do Javy. viz. zkušenost na jeho blogu http://amix.dk/blog/post/19577 Jedná se asi o jedno z největších produkčních nasazení node.js

Pokud někdo něco chce asynchronně programovat, tak ať sáhne po technologiích, které nemají takové problémy jako je např. pro Javu – Netty, EventMachine pro Ruby, Tornado pro Python atd. sice problém těchto jazyků je, že obsahují spoustu knihoven co mají blokující kód, ale pokud člověk ví co dělat, tak ví jakému kódu se vyhnout, aby nebyl blokující.

Možná node.js jednou bude stejně použitelný jako jiná řešení a momentálně bohužel není. Obsahuje spoustu chyb viz. memory leaky na zmiňovaném blogu, je dost mladý, nestabilní atd. toto se možná jednou vyřeší, ale chyby JavaScriptu bohužel ne. Možná přijde nový standard, který V8 bude podporovat, který vyřeší spoustu problému JavaScriptu, ale možná taky ne… Chápu, že tohle není problém pro všechny. Jsou lidi co mají JavaScript rádi a líbí se jím hacky jakým simulují objekty, jmenný prostory, dědičnost atd.

node.js je prostě buzz word a osobně jsem si myslel buhví co to je, ale po vyzkoušení a následném research zjišťují, že je to skutečně jen buzz word a nenašel jsem důvod proč node.js použít. Naopak jsem našel důvody proč se mu vyhnout.

Jakub

Inu Tomáši – někdo má rád holky, jiný zase vdolky. Není nutné, aby celý svět používal jediný jazyk/framework.

Některé zmiňované problémy jsou vnímany jako přednost, např. C-část node.js single-threaded není, zakládá vlákna např. pro obsluhu blokujících IO, nicméně JS/V8 vás izoluje do single-threaded sandboxu – a je to dobře. Jiné jsou řešitelné a dostaneme se k ním v pozdějších dílech (multi-core procesory, moduly), jiné problémem nejsou (GC ve V8 je opravdu propracovaný, generační a v příští verzi asi i v separátním threadu).

Vás možná node.js neoslovil, ale MNOHO jiných kvalitních programátorů ano. A už to samo o sobě je příslibem toho, že nad node.js vznikne spousta zajímavých projektů a silný ekosystém. Ostatně – jsem si jistý, že před pár lety když nabíralo na popularitě Ruby (díky Railsům) tak se mu nadávalo ještě hůře. A kdo se směje teď? :)

Mastodont

Ano, to je dobrá otázka – kdo se směje?
http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

karmi

Díky za článek!

Když jsem onehdá Node.js instaloval, cvičení s `chown /usr/local` podle návodu autora npm se mi nelíbilo, ale fungovala rozumnější metoda popsaná zde: https://gist.github.com/579814#file_yet_another_option.sh

Jakub

Díky za odkaz Karmi! Jsou další, alternativní způsoby, ale nechtěl jsem to pro začátek komplikovat…

Oldřich Vetešník

Chci se jenom zeptat, na čem jsi to instaloval? Vypadá to na Mac OS X, ale jistý si nejsem. (Doufám, že nevadí, že tykám :).

Díky.
Oldřibřich.

Jakub

Oldo – nevadí. :) Otisky obrazovky jsou z OS X, na kterém jsem instaloval. Kromě toho jsem instaloval také na Ubuntu a CentOSu. Pokud máš nějaké konkrétní otázky/problémy s instalací, klidně se můžeš zeptat tady v komentářích.

Oldřich Vetešník

Super, díky, vyzkouším. :)

Michal Augustýn

Díky za článek a opožděně i za pěknou přednášku na WebExpo Digest ;-)

1) Když je nativní vrstva nad V8 tak tenká, nechystá se i port pro Windows? (Ptám se proto, protože jsem líný Windows člověk a nechce se mi zaplevelovat systém Cygwinem.)

2) Není mi moc jasný „životní cyklus“. Když „vše“ běží v jednom vlákně, tak jak to přesně funguje? Pokud se každý request zpracovává v jiném vlákně, tak je určitě třeba nějak synchronizovat minimálně přístup ke globálnímu objektu. Nebo se vždy zpracovává max. jeden request (tj. uvnitř anonymní metody předané to http.createServer se nachází právě jeden request) ? Nebo se sychronizace vyřeší tím, že se běhové prostředí JavaScriptu forkne nebo „forkne“?
Možná by pomohl kratičký příklad, který by počítal celkový počet requestů a který ukazuje použití proměnné (v globálním objektu? jde to?), která je platná jen po dobu života jednoho requestu.

3) Sílu JavaScriptu vidím hlavně v tom, že je možné použít stejný jazyk pro frontend i backend. Na přednášce jsi dále zmiňoval možnost psát asynchronně, tj. předávat všude (anonymní), které představují continuation, a že je na to API od začátku navrženo.
Stejný způsob lze ale použít IMHO v dalších jazycích, které mají k dispozici asynchronní API, např. v C#/.NET. Nevím, jestli jsi viděl CTP C# 5, ale tam dokonce zavádí klíčová slova async a await, díky kterým ty ošklivé continuations vygeneruje přímo kompilátor a kód je tak o řád čistější. Tomu IMHO nemůže JavaScript konkurovat (a to říkám jako velký JavaScriptový větrák ;-)).

Daniel Steigerwald

ad bod tři

jj, naprostej souhlas, ale stejně, js nás vždy překvapí: https://github.com/jed/fab ;)

Daniel Steigerwald
Michal Augustýn

LISP reloaded aneb závorkové peklo :-)

dasim

Objevil jsem náhodou http://jsapp.us/ – může se hodit pro zkoušení příkladů a vůbec hraní si v rychlosti s node.js

Martin Malý
echy

Už nevím kde jsem tu informaci vygooglil, ale každopádně v Ubuntu pomůže překompilovat node.js s GCC_VERSION=44, pak debug mód šlape jak hodinky.

OJ

:-) text musí být dlouhý alespoň 4 znaky.

ptica

dari se mi naklikat petikacka na den, vps za rok za ~360, jak pise jakub v clanku ale ne. nevite, jak na to?

Václav Klecanda

Vypocet se zastavi na breakpointu, ale at dam continue, stepin, stepover,… nestane se nic. Ani na klient se nic neposle, takze se toci stale dal. Kdyz koukam na stdout node-inspectoru, tak do nej ty udalosti s browseru chodi (napr.: {„method“:“De­bugger.stepIn­to“,“id“:35} … Debugger.resumed : {}). Zkousim to na linuxu, v chromium browseru. Zkusil jsem to i v chromu, ale stejny vysledek. Netusi nekdo co delam blbe?

Václav Klecanda

Sorry, nevsim jsem si prve postu od Vojta Grec. Kazdopadne pro ubuntaky PPA repo:
sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs npm

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.