Programista 19 NodeJS
Programista 19 NodeJS
Sebastian Rosik
Wprowadzenie do Node.js
Node.js ostatnimi czasy zyskuje coraz bardziej na popularności, częściowo dzięki
powszechności JS oraz możliwościom, jakie daje. Postaram się w prosty sposób
wyjaśnić, czym jest oraz jak działa Node.js czytelnikom, którzy jeszcze nie mieli z
nim styczności. Przedstawię, w jaki sposób pisać skrypty, instalować oraz tworzyć
własne moduły, a na końcu zaprezentuję prostą aplikację chat klient – serwer.
N ZASTOSOWANIA SIECIOWE
ode.js jest platformą bazującą na silniku V8 stworzonym przez fir-
mę Google na potrzeby swojej przeglądarki Google Chrome. V8 jest
obecnie jednym z najszybszych silników JavaScript dostępnych na W przypadku zastosowań serwerowych, w relacji klient – serwer zdecydo-
rynku. Sam Node.js ujrzał światło dzienne w 2009 r. i jak na tak młodą platfor- waną większość czasu zajmuje komunikacja pomiędzy wszystkimi punktami
mę niezwykle szybko zdobywa popularność. sieci, z której korzysta nasza aplikacja (np. połączenia z bazą danych, dostęp
Node.js jest oczywiście oparty o JavaScript, ale to wcale nie oznacza, że do dysku, logger etc.). Czas operacji czysto obliczeniowych jest jednak o wiele
jest to po prostu przeglądarka internetowa, do dyspozycji mamy silnik JS, nie mniejszy. Oczywiście nie jest to twarda reguła, a jedynie najczęściej występu-
uświadczymy wsparcia dla drzewa DOM czy styli CSS, jak to ma miejsce w jący przypadek w aplikacjach serwerowych.
przeglądarkach. Mimo że język skryptowy jest ten sam, to jednak główna za- Node.js jest sterowany zdarzeniami i nie blokuje operacji wejścia/wyjścia,
sada działania jest diametralnie inna, w szczególności jeśli chodzi o możliwo- dlatego też tak dobrze sprawdza się w rozwiązaniach serwerowych.
ści obu platform, jak i ich restrykcje. W przeglądarce internetowej na przykład
mamy ograniczenia związane z Cross-Domain Policy, brakiem modułów czy
dostępu do sprzętu. W Node.js nic nas pod tym względem nie ogranicza. Pod-
sumowując, do dyspozycji mamy sam język JavaScript na silniku V8 oraz wbu-
dowane moduły do obsługi sieci, systemu plików, procesów itp. oraz masę
modułów. Nic nas nie ogranicza pod względem możliwości.
PLUSY I MINUSY JAVASCRIPT ORAZ funkcjonowania tej platformy. Node.js jedynie daje nam możliwość pisania
NODE.JS skryptów w jednym wątku, który nie będzie blokowany przez operację wyj-
ścia/wejścia. Oznacza to, że możemy jednak stworzyć skrypt, który będzie się
W zależności od tego, kogo się zapyta i od jakiej strony się spojrzy, język Java- blokował. Możemy to zrobić umyślnie, poprzez wykorzystanie synchronicz-
Script jest jednocześnie olbrzymim plusem, jak i minusem. Wiele osób, przy- nych funkcji (o których więcej w dalszej części artykułu), bądź nieumyślnie,
zwyczajonych do języków o twardym typowaniu, odnosi się z niechęcią do JS poprzez błąd w kodzie lub zbyt dużą ilość obliczeń (np. parsowanie bardzo
ze względu na jego dynamiczność. Pozwala to co prawda dość szybko pisać dużego pliku).
kod, nie przejmując się typowaniem, ale odbija się to niestety na prędkości Oczywiście na mikroskopijnym poziomie już każde wywołanie jakiejkol-
działania oraz możliwości wystąpienia błędów w kodzie. wiek funkcji blokuje wątek na drobny ułamek czasu, co jest jednak jak najbar-
dziej oczekiwanym działaniem, jednak wiele wywołań takich funkcji, np. w
Plusy Minusy pętli, spowoduje całkowite zablokowanie wątku.
To samo tyczy się wywołania pojedynczej funkcji, która musi dokonać
PP Bardzo popularny język, wiele PP Ze względu na dynamikę języka, skomplikowanych obliczeń. By tego uniknąć, zawsze gdy istnieje taka możli-
osób pracujących ze środowi- łatwo napisać niechlujny kod.
skami przeglądarkowymi poczu- PP Dla osób, które do tej pory pisały wość, powinniśmy korzystać z rozwiązań asynchronicznych.
je się jak w domu. jedynie w np. PHP, może być to Funkcje w wersjach synchronicznych mogą się nam przydać w przypad-
PP Idealny do zastosowań siecio- trudna przeprawa. ku, gdy piszemy narzędzia czy aplikacje, które nie będą rozwiązaniami serwe-
wych, gdzie wymagane jest sta- PP Jako że Node.js istnieje zaledwie 4 rowymi, czyli wszędzie tam, gdzie dostęp do zasobów odbywać się będzie
łe połączenie z serwerem, bądź lata, nie ma on zbyt wielu napraw-
szybkość odpowiedzi. dę dojrzałych i komercyjnie stoso- lokalnie, a czas dostępu będzie minimalny. Funkcje synchroniczne w takim
PP Olbrzymia ilość modułów. wanych na dużą skalę bibliotek. wypadku sprawdzą się lepiej pod kątem czytelności kodu, jak i jego prostoty
(mniej zagnieżdżonych funkcji).
26 / 12 . 2013 . (19) /
WPROWADZENIE DO NODE.JS
Listing 1. Przykład, w jaki sposób można zablokować wątek, czyli Listing 4. Skrypt czytający plik tekstowy napisany w JavaScript
jak strzelić sobie w kolano (wersja synchroniczna)
ASYNCHRONICZNOŚĆ »» Dane z jednego zapytania mogą być dostępne bezpośrednio dla drugie-
go zapytania.
JavaScript ukazuje swoją moc w asynchroniczności, dzięki której nasz skrypt
nie jest blokowany, gdy musi wykonać jakieś zadanie związane np. z dostę- PRZYKŁAD PROSTEGO SERWERA
pem do danych. HTTP
Poniżej dwa listingi plików, jeden przedstawiający skrypt napisany w PHP,
drugi w JS, oba skrypty wykonują dokładnie to samo zadanie, ale jednocze- W poprzednim przykładzie (Listing 4) skrypt odczytał plik, wypisał jego war-
śnie w diametralnie odmienny sposób. tość, a następnie zakończył działanie. Na Listingu 5 został przedstawiony naj-
Skrypt PHP jest wykonywany synchronicznie, to znaczy, że każde następ- prostszy możliwy serwer HTTP, jaki można stworzyć w Node.js. W tym kon-
ne zadanie czeka, aż pierwsze zakończy działanie. W przypadku skryptu JS kretnym przykładzie w pierwszej kolejności sięgamy po moduł serwera HTTP.
do odczytania pliku została użyta funkcja asynchroniczna, przez co zawartość Serwer HTTP tworzymy poprzez funkcję createServer, która jako argu-
pliku zostanie zwrócona w argumencie funkcji callback po pewnym czasie, ment przyjmuje funkcję, która zostanie wywołana za każdym razem, gdy jakiś
bez wstrzymywania wątku. Efekt tego będzie taki, że, mimo iż funkcja wy- klient wyśle zapytanie do serwera. Gdy skończymy inicjalizowanie naszego
świetlająca napis “Zawartość pliku:” została umieszczona na samym końcu, serwera, możemy wywołać metodę listen, co spowoduje rozpoczęcie na-
zostanie jednak wywołana przed wywołaniem funkcji, która wyświetli zawar- słuchiwania na podanym porcie i adresie, jeśli go podaliśmy.
tość pliku.
Listing 5. Prosty serwer HTTP
Listing 2. Skrypt czytający plik tekstowy napisany w PHP
var http = require('http');
// req – zawiera dane dotyczące zapytania
<?php
// res – zawiera właściwości i funkcje,
$name = "test.txt";
// dzięki którym jesteśmy w stanie
$h = fopen( $name, 'r');
// odpowiedzieć na zapytanie
$text = fread( $h, filesize( $name ) );
var visits = 0;
echo "Zawartość pliku:";
http.createServer(function( req, res ){
echo $text;
if ( req.url == '/' ) {
?>
visits++;
res.end('Jesteś gościem numer: '+visits+'\n');
Listing 3. Skrypt czytający plik tekstowy napisany w JavaScript }
(wersja asynchroniczna) }).listen(8080);
var fs = require('fs');
var name = 'test.txt';
fs.readFile( name, 'utf8', function( err, text ){
console.log( text );
});
console.log('Zawartość pliku:');
/ www.programistamag.pl / 27
PROGRAMOWANIE APLIKACJI WEBOWYCH
mamy zainstalowany kompilator i system *nix). Jeżeli chcemy samemu skom- Po jej wywołaniu NPM zapyta nas o kilka podstawowych informacji (nazwa
pilować Node.js pod systemem Windows, będziemy musieli się zaopatrzyć w modułu, wersja, autor etc.). Komenda ta utworzy plik package.json, który bę-
Microsoft Visual Studio oraz Python 2.6. Link do strony z informacją na temat dzie zawierał wszystkie informacje, które wcześniej podaliśmy. Wszelkie zależ-
instalacji ze źródeł znajduje się na końcu artykułu. ności w postaci innych modułów NPM będą miały swój wpis w tym pliku, co
umożliwi bardzo prostą instalację naszego modułu w nowej lokacji poprzez
Uruchamianie skryptów wydanie komendy:
node plik.js Po jej wydaniu npm przeczyta wartość pola “dependencies” w pliku pac-
kage.json, po czym zainstaluje wszelkie zależności w katalogu node_modules,
Możemy także wydać powyższe polecenie z pominięciem rozszerzenia który zostanie utworzony w głównym katalogu naszego modułu.
".js" – jest ono całkowicie opcjonalne. Jeżeli nie podamy lokacji pliku jako Poniżej lista kilku z najczęściej używanych komend NPM:
argumentu, Node.js zostanie uruchomiony w trybie interaktywnym – REPL »» npm search zapytanie – szuka w repozytorium modułu pasującego do
(read-eval-print-loop). podanego zapytania
Jest to interaktywne środowisko programowania znane z wielu innych »» npm install – instaluje wszystkie moduły zdefiniowane w package.json
języków, pozwala na wpisywanie komend, wykonywanie wprowadzonego »» npm install nazwa-modulu – instaluje podany moduł w katalogu
kodu i wyświetlanie wyniku działania. node_modules
»» npm install nazwa-modulu – -save – instaluje podany moduł w katalogu
node_modules, a następnie zapisuje jego referencje w pliku package.json
»» npm list – wypisuje wszystkie zainstalowane moduły
28 / 12 . 2013 . (19) /
WPROWADZENIE DO NODE.JS
<!DOCTYPE html>
By korzystać z tego samego skryptu po stronie Node.js i przeglądarki, pierw- <html>
szą rzeczą, z jaką trzeba się zmierzyć, jest sposób rozróżnienia obu środowisk. <head>
<meta charset="utf8"/>
W Node.js nie mamy globalnego obiektu window, natomiast po stronie prze- <title>Chat</title>
glądarki nie dysponujemy systemem modułów ani nie mamy dostępu do </head>
<body>
obiektu procesu. Rozróżnienie obu środowisk zatem ograniczy się do spraw-
<form action="/room.html" method="GET">
dzenia, czy na danym środowisku istnieją odpowiednie obiekty. <input type="text"
Naszym współdzielonym skryptem będzie plik consts.js, który będzie za- name="nick"
placeholder="Twój nick"/>
wierał stałe, używane w komunikacji pomiędzy serwerem a klientem. <button type="submit">
Pierwszym etapem tworzenia modułu jest opakowanie naszego kodu w Dołącz
</button>
samowywołującą się funkcję, która w środowisku przeglądarkowym ograni- </form>
czy zasięg zmiennych tylko do tej funkcji, dzięki czemu nie będzie nam groziła </body>
</html>
potencjalna kolizja ze zmiennymi innych skryptów. Nie jest to oczywiście coś,
co musimy zrobić, ale zdecydowanie daje nam pewność, że nie wpadniemy
Listing 11. Plik room.html
w potencjalną pułapkę.
Opakowywanie zmiennych w samowywołującą się funkcję nie jest ko- <!DOCTYPE html>
niecznie w przypadku modułów Node.js, gdyż tam zmienne lokalne nie mają <html>
<head>
możliwości przebicia się do innych modułów. My natomiast i tak to zrobimy <meta charset="utf8"/>
ze względu na fakt współdzielenia tego pliku na dwóch środowiskach. <title>Chat</title>
<script src="consts.js"></script>
<script src="client.js"></script>
Listing 8. Samowywołująca się funkcja <link rel="stylesheet"
type="text/css"
(function(){ href="main.css"/>
var consts = { /**/ } </head>
})(); <body onload="app.init()">
<ul id="messages"></ul>
<footer>
Drugim etapem jest detekcja środowiska, w jakim skrypt został urucho- <input type="text" diabled />
</footer>
miony dla Node.js.
</body>
Wybór poniższych globalnych zmiennych, które biorą udział w detekcji, </html>
jest arbitralny, zatem nadadzą się jakiekolwiek globalne zmienne, jakie wystę-
pują w pierwszym środowisku, ale już nie w drugim. Listing 12. Plik main.css
/ www.programistamag.pl / 29
PROGRAMOWANIE APLIKACJI WEBOWYCH
30 / 12 . 2013 . (19) /
WPROWADZENIE DO NODE.JS
/ www.programistamag.pl / 31
PROGRAMOWANIE APLIKACJI WEBOWYCH
});
socket.on('close', function(){
console.log('Socket closed: %s', id);
delete sockets[id];
});
(function(){
var consts = {
USR_MSG : 1,
SYS_MSG : 2,
JOIN : 3
}
W sieci
PP Gotowe instalatory oraz paczki do pobrania:
http://nodejs.org/download/
PP Instalacja ze źródeł:
https://github.com/joyent/node/wiki/Installation
PP SSJS:
http://en.wikipedia.org/wiki/Comparison_of_server-side_JavaScript_
solutions#Server-side_JavaScript_use
PP Pełne API Node.js: Rysunek 6. Zakładka Frames prezentuje dane, jakie zostały wysłane i odebrane
http://nodejs.org/api/ poprzez WebSocket po ustanowieniu połączenia
Frontend developer, obecnie pracuje we wrocławskim oddziale RST sp. z o.o. sp. k, gdzie
rozwija aplikacje przeglądarkowe. Dawniej brał udział w projektowaniu gier mobilnych JAVA
od strony wizualnej oraz gameplay’u. Dziś pisze głównie aplikacje HTML5 na przeglądarki
oraz zgłębia tajniki node.js. Hobbystycznie zajmuje się tworzeniem grafiki 2D.
32 / 12 . 2013 . (19) /