JavaScript na serveru: Architektura a první Hello World

node.js logo

V dalším díle seriálu se dozvíte něco málo o architektuře Node.js, o asynchronním programováním a o významu pojmů, které se vážou speciálně k Node.js. V průběhu článku si navíc napíšeme první skript, tradiční Hello World.

Seriál: Node.js - s JavaScriptem na serveru (13 dílů)

  1. JavaScript na serveru: Začínáme s Node.js 23.11.2010
  2. JavaScript na serveru: Patří budoucnost Node.js? 21.9.2012
  3. JavaScript na serveru: Architektura a první Hello World 5.10.2012
  4. JavaScript na serveru: moduly a npm 12.10.2012
  5. JavaScript na serveru: začínáme programovat e-shop 19.10.2012
  6. JavaScript na serveru: MongoDB, Mongoose a AngularJS 26.10.2012
  7. JavaScript na serveru: Testování a kontinuální integrace 2.11.2012
  8. JavaScript na serveru: REST API 9.11.2012
  9. JavaScript na serveru: implementace REST API 16.11.2012
  10. JavaScript na serveru: nástroje a dokumentace 23.11.2012
  11. Začínáme s AngularJS 30.11.2012
  12. AngularJS direktivy a testování 7.12.2012
  13. JavaScript na serveru: CoffeeScript a šablonovací systémy 14.12.2012

Node.js je platforma pro vývoj webových aplikací. Pojem platforma zahrnuje i webový server, není tedy nezbytně nutné žádný zvláštní webový server (jako je třeba Apache pro PHP) k Node.js pro provoz instalovat, nicméně v produkčním nasazení je lepší Node.js používat společně s jiným webovým serverem, který zajistí minimálně vyřizování požadavků na statické soubory, které by neměly být zpracovány přes Node.js. Velmi často se pro tyto účely používá webový server nginx. Postup pro jeho instalaci a nastavení pod Windows si můžete přečíst na českém blogu o Node.js. V dalším průběhu seriálu budu používat pouze Node.js bez nginx.

Pouze jedno vlákno

Pokud se o Node.js trochu zajímáte, určitě jste narazili na pojem single-thread. To znamená, že Node.js pracuje pouze v jednom vlákně, což je rozdíl oproti častějším případům, kdy webový server odpověď na každý požadavek zpracovává v jiném vlákně. Známe to všichni například z kombinace PHP + Apache, kdy pro každý požadavek Apache alokuje určité množství paměti, ve které PHP zpracuje daný HTTP požadavek. I v případě, že je odpověď záležitostí jednoduchého skriptu, musí dojít např. k načtení konfigurace projektu, inicializace spojení s databází, načtení celého frameworku, routeru atd., což bývá často zbytečné a neefektivní.

Protože Node.js pracuje pouze v jednom vlákně, při spuštění aplikace (před zpracováním prvního HTTP požadavku) dojde k načtení a inicializaci všeho potřebného a jakmile je vše načteno, Node.js poslouchá příchozí požadavky a ty pak směřuje na konkrétní controllery a akce (v případě MVC architektury). Vše objasní následující ukázka:

var http = require('http');
console.log('Nacteni konfigurace, databaze, lokalizace ap.');
http.createServer(function (req, res) {
  console.log('Zpracovani pozadavku z URL: ' + req.url);
  res.end('Hello World');
}).listen(1337);

Nejprve přes funkci require() načteme modul http, který vytváří webový server a zpracovává HTTP požadavky. Metoda createServer() vytváří objekt reprezentující server. Přijímá jako jediný parametr anonymní funkci, která obsahuje dva parametry: parametr req reprezentuje požadavek, res odpověď. Metoda listen() pak říká, že má server poslouchat na portu 1337 na příchozí HTTP požadavky.

Tento soubor uložte třeba jako server.js, vložte ho třeba do složky C:zdrojak. Spusťte příkazový řádek (příkaz cmd) a přejděte do složky s tímto skriptem (příkaz cd C:zdrojak). Zde pak projekt spustíte přes příkaz node server.js.

Následně v prohlížeči přejděte na adresu http://localhost:1337. Měli byste vidět text “Hello World”, který byl předán metodě res.end(), která odešle odpověď serveru. V konzoli navíc uvidíte text “Zpracování z požadavku: /”. Jakýkoliv další požadavek bude zpracováván uvnitř anonymní funkce, jejíž volání je již unikátní pro každou URL a každého uživatele, jak je to obvyklé. Po spuštění se vám vypíše obsah vložený do metody console.log(). Cokoliv napíšete do skriptu server.js mimo obsahu anonymní funkce předané funkci createServer() bude zavoláno. Můžete zde připravit spojení s databází, načíst framework, načíst lokalizaci webu atd.

Požadavky jsou zpracovány v pořadí, v jakém přicházely na server, a že jsou opravdu zpracovány v jednom vlákně, se přesvědčíme jednoduchým pozměněním skriptu:

var http = require('http');
var pocet = 0;
http.createServer(function (req, res) {
  res.end(++pocet + '');
}).listen(1337);

Při každém načtení prohlížeče se vypíše vyšší hodnota (pravděpodobně se vám bude zobrazovat po každém načtení prohlížeče číslo o 2 vyšší než to předchozí, protože prohlížeč posílá navíc požadavek na favicon.ico, takže se zpracovávají dva požadavky).

Asynchronní zpracování

Dále se můžete o Node.js dočíst, že používá událostmi řízený (event-driven) neblokující I/O model. Co to přesně znamená, si opět vysvětlíme na příkladu s PHP.

V PHP píšete obvykle jeden příkaz na každý řádek. Jakmile skript zpracuje jeden příkaz, pokračuje dále. Podstatné je, že dokud není dokončen předchozí příkaz, není možné zpracovat ten další, protože jeden příkaz blokuje ostatní. Takže např. po dokončení objednávky v e-shopu nejprve vložíte objednávku do databáze, čekáte, dokud nepřijde odpověď od databáze, dále odešlete e-mail správci, počkáte, dokud neodejde, pak e-mail zákazníkovi atd.

V Node.js můžete psát také tímto způsobem, ale pouze tam, kde nedochází k zpracování požadavků uživatele (např. při zmíněném načítání konfigurace, lokalizaci, inicializaci frameworku ap.). V případě zpracování konkrétního HTTP požadavku už vždy musíte používat asynchronní metody a funkce, protože pracujete v jednom vlákně a synchronní metody zablokují celý server, dokud nejsou zpracovány.

Co si představit pod pojmem asynchronní zpracování? Všechny I/O operace v Node.js jsou napsány tak, aby server neblokovaly. Podívejte se na příklad čtení dat z disku:

var fs = require('fs');
fs.readFile('soubor.txt', function(err, data){
  console.log('A');
});
console.log('B');

Co myslíte, v jakém pořadí se vypíší písmena do konzole? Pokud hádáte, že bude pořadí „B, A“, pak máte pravdu. Ve chvíli, kdy skript narazí na metodu readFile(), spustí na pozadí čtení z disku a skript pokračuje ihned dále. Až se data z disku načtou, zavolá se anonymní funkce předaná jako druhý parametr a předá se jí výsledek zpracování souboru. Teprve tehdy se do konzole vypíše písmeno A.

V Node.js tedy existuje něco jako fronta událostí, které se volají podle toho, jak byly do fronty vkládány. Ve svých programech byste měli vždy psát neblokující kód a operace, které mohou zabrat více času, pak řešit jiným způsobem (nejčastěji spuštěním samostatného procesu přes balíček child_process, což je obdoba Web Workers z klientského JavaScriptu, o tom někdy v pozdějších dílech seriálu).

Poslední zmínka už jen k I/O operacím a jejich fungování v Node.js. Operace jako práce s databází, čtení a zápis se spouštějí zcela mimo frontu událostí. Spouštějí se na pozadí a ve vláknech tak, jak je to běžné i u ostatních jazyků. Pokud tedy zadáváte dotaz na databázi trvající třeba 2 vteřiny, neznamená to, že je server na 2 vteřiny zablokován. Vše pokračuje dále, pouze asynchronní funkce čeká na to, až databáze zpracuje a vrátí výsledky a pak bude pokračovat dále.

Co dále?

Dnešní díl byl hodně teoretický a je možné, že některé zmíněné části architektury Node.js vám nejsou zcela jasné. Netrapte se tím. V dalších dílech se k dnešním pojmům určitě ještě mnohokrát vrátím a rozšířím jejich výklad na dalších příkladech. V příštím díle se můžete těšit na seznámení s nástrojem npm, přes který můžete snadno instalovat tisíce různých modulů.

Jakub pracoval na několika zajímavých projektech, za nejvýznamnější považuje vytvoření e-commerce řešení Shopio.cz. Poslední rok se plně věnuje Node.js, frameworku AngularJS a NoSQL databázím.

Komentáře: 20

Přehled komentářů

LiborS stejne jako na klientovi
Jakub Mrozek Re: stejne jako na klientovi
julochrobak single threaded ?
Ondřej Štoček Re: single threaded ?
julochrobak Re: single threaded ?
TMa Node.js v browseru
Jakub Mrozek Re: Node.js v browseru
langpa Re: Node.js v browseru
TMa Re: Node.js v browseru
Razor Re: JavaScript na serveru: Architektura a první Hello World
LiborS Re: JavaScript na serveru: Architektura a první Hello World
langpa Re: JavaScript na serveru: Architektura a první Hello World
Rax Nesouhlasím
langpa Re: Nesouhlasím
langpa Re: Nesouhlasím
Rax Re: Nesouhlasím
srigi Nie len Hello World!
Martin Hassman Re: Nie len Hello World!
Jakub Mrozek Re: Nie len Hello World!
janpoboril React.PHP
Zdroj: http://www.zdrojak.cz/?p=3711