w Praktyce
10 godz. 44 min · Node.js · Full-stack i Programowanie
Piotr PalarzWeb DeveloperW kursie tym poznasz platformę Node.js od podstaw, aż po bardziej zaawansowane koncepcje. Zaczniemy od omówienia czym jest Node, a także jakie może być zastosowanie tej technologii. Następnie przejdziemy przez proces instalacji i napisanie swojego pierwszego skryptu. Już na samym początku dokładnie omówimy tworzenie własnych modułów, gdyż jest to wiedza niezbędna, by dobrze zrozumieć funkcjonowanie Node. Następnie dowiesz się czym są zdarzenia, jak działa model “publish / subscribe”, a także czym jest “event-driven development”. Chwilę później omówimy pracę z buforami, stream’ami, a także ze standardowym wejściem i wyjściem. Ta wiedza pozwoli Ci zrozumieć jak tworzone aplikacje mogą otrzymywać od użytkownika dane oraz jak je wyświetlają.
Niezwykle ważnym rozdziałem będzie ten, poświęcony pracy z systemem plików. Szczególnie dla dewelopera, pracującego dotychczas z językiem JavaScript wyłącznie w środowisku przeglądarki internetowej. Node pozwala bowiem tworzyć nowe pliki, zapisywać w nich dane oraz odczytywać i usuwać pliki i katalogi. Przy wszystkich tych operacjach, niezwykle ważna jest jednak asynchroniczna natura Node. Dowiesz się jak działa, a także jakie są jej zalety. Na tym etapie nie zabraknie oczywiście praktycznego projektu, którym będzie aplikacja typu CLI (Command Line Interface). Pozwoli nam ona grupowo zmienić nazwy wielu plików, według podanego wzorca.
W kolejnym rozdziale poruszymy fundamentalną dla Node kwestię, mianowicie tworzenie serwerów sieciowych. Zaczniemy od najniższego poziomu, tworząc prosty serwer bazujący na protokole TCP/IP. Wiedza w jaki sposób Node radzi sobie z takim zadaniem, pozwoli później lepiej zrozumieć wyższe warstwy, takie jak np. HTTP czy WebSockets. Chwilę później stworzymy swój pierwszy serwer HTTP, do którego będzie można wysyłać zapytania wprost z przeglądarki internetowej. Omówimy również jak w Node wykorzystać bezpieczne szyfrowanie HTTPS.Na tym etapie będziesz już miał solidną wiedzę jak pracować z Node, jednak zanim przejdziemy dalej, zatrzymamy się, by omówić jak dokładnie działa Node.js, a także jak ta platforma została zbudowana. Dwie dość obszerne lekcje, będą być może jednymi z najważniejszych w tym kursie. Dowiesz się w nich czym jest, a także jak działa jednowątkowa pętla zdarzeń, czym jest proces i wątek, a także zobaczysz kod źródłowy Node.js i wszystkie bloki budulcowe, z jakich Node się składa. To naszym zdaniem niezwykle ważny temat, często jednak pomijany w wielu materiałach. Dzięki dogłębnemu zrozumieniu jednowątkowej natury języka JavaScript i asynchroniczności Node, będziesz mógł tworzyć dużo lepsze aplikacje.
Node.js posiada kilkanaście wbudowanych modułów, z których w dowolnej chwili można skorzystać. Wszystkie jednak dają nam dużą, niskopoziomową kontrolę, ale czasami sporo kodu należy napisać, by zrealizować jakieś zadanie. Jest to jednak świadomy wybór twórców Node, gdyż całą resztę świetnych rozwiązań, dopisuje nieustannie ogólnoświatowa społeczność deweloperów. Zdecydowana większość z modułów ląduje w rejestrze npm. Jest to genialny package manager, który pozwoli nam wyszukiwać, pobierać i aktualizować niezliczoną ilość modułów. Dowiesz się zatem jak korzystać z npm, a chwilę później zaczniemy wykorzystywać zgromadzone tam moduły w dalszej pracy.Jednym z najpopularniejszych modułów jest express.js, który pozwala w bardzo prosty sposób tworzyć serwery HTTP. Grzechem byłoby zatem z niego nie skorzystać. Dowiesz się wszystkiego co niezbędne, by zacząć tworzyć własne aplikacje bazujące na protokole HTTP z użyciem express.js, a także kilku dodatków do tego systemu. Zobaczysz jak routować zapytania, jak korzystać z middleware czy serwować statyczne pliki. Następnie omówimy współpracę z bazą danych MongoDB i z jej wykorzystaniem stworzymy API typu REST. Stworzona aplikacja pozwoli odczytywać dane z bazy i przesyłać je do klienta w formacie JSON, a także dodawać nowe dane, aktualizować i usuwać je. Wszystko to zgodnie z dobrymi praktykami pracy z REST.
Chwilę później czeka Cię kolejny praktyczny projekt - skracacz linków. Stworzymy wspólnie aplikację, która pozwoli skrócić dowolny adres URL do krótkiej formy. Oczywiście będzie działać również w drugą stronę! Kiedy przejdziemy pod skrócony adres, przekieruje nas do odpowiedniej witryny. Node.js to platforma wręcz stworzona do tworzenia aplikacji typu real-time, dlatego w kolejnym rodziale podejmiemy temat technologii WebSockets. Dowiesz się jakie są jej zalety, a także jak pracować z nią po stronie serwera i klienta. Tutaj czeka nas kolejny praktyczny, niezwykle ciekawy projekt. Wykonamy bowiem czat grupowy. Aplikacja ta pozwoli dowolnej ilości użytkowników podłączyć się do czatu podając swój nick, a następnie wysyłać widoczne dla wszystkich wiadomości. Zaimplementujemy nawet takie rozwiązania jak wyświetlanie statusów o dołączeniu kogoś do czatu, a także o jego opuszczeniu.W przedostatnim rodziale tego kursu podejmiemy tematykę dobrych praktyk pracy z Node.js. Na początku omówimy najważniejsze konstrukcje nowej specyfikacji EcmaScript 2015, które są znakomicie wspierane w Node. Chwilę później omówimy jak korzystanie z Promises uprości, a także ulepszy nasz kod. Wśród dobrych praktyk nie zabraknie również informacji o debugowaniu aplikacji. Zobaczysz sprawdzone sposoby, by znaleźć błędy lub lepiej, krok po kroku, zrozumieć jak działa napisany wcześniej kod. Dowiesz się również jak pracować z błędami, by Twoje aplikacje działały w sposób przewidywalny.
Ostatni rozdział w całości został poświęcony temu, co zwykle jest pomijane w innych materiałach, mianowicie wdrażaniu aplikacji do produkcji. Przez cały ten kurs pracować będziemy lokalnie, lecz kiedy aplikacje są już gotowe, wypadałoby udostępnić je światu. Wdrażanie aplikacji napisanych z użyciem Node.js nie jest jednak tak oczywiste, jak np. wgrywanie WordPress’a u wybranego hostingodawcy. Ty będziesz miał jednak możliwość zobaczyć, jak wdrożyć napisany przez nas grupowy czat na platformie Heroku. Jest to bardzo popularny serwis działający jako PaaS (Platform as a Service). Za darmo będziesz mógł w ciągu kilku chwil uruchomić swoją aplikację.Zobaczysz o co należy zadbać, by wszystko poszło gładko. Serwisy typu PaaS dbają o bardzo wiele aspektów wdrażania i serwowania naszych aplikacji, takich jak bezpieczeństwo oraz nieustanną dostępność. Mają jednak pewne ograniczenia. Z tego powodu, dowiesz się również jak wdrożyć swoją aplikację na serwerze wirtualnym VPS z systemem Ubuntu Server. Takie rozwiązanie daje nam całkowitą kontrolę, ale także obarczone jest większą odpowiedzialnością. Zaczniemy od instalacji na serwerze platformy Node.js, systemu kontroli wersji GIT, a także innych niezbędnych modułów
Następnie zobaczysz jak skonfigurować swoje lokalne środowisko tak, by za pomocą GIT’a wysyłać kod do zdalnego serwera, a potem jednym poleceniem wdrażać go do produkcji. Dowiesz się również jak jednocześnie serwować wersję produkcyjną oraz developmencką. W rodziale tym poruszymy również inne kwestie, takie jak procesy potomne czy tworzenie klastrów. Dzięki tej wiedzy, będziesz mógł maksymalnie wykorzystać dostępne zasoby serwera. Na sam koniec tego kursu rzucimy okiem również na inne, nie przedstawione wcześniej zastosowania Node, a także nakreślimy dalszą drogę nauki w tym zakresie.
Kurs ten jest dla wszystkich osób, które dobrze czują się w technologiach frontendowych, tj. HTML, CSS i JavaScript, a teraz chcą rozpocząć swoją przygodę z back-endem. Im zatem lepiej znasz język JavaScript, tym więcej wyciśniesz z Node, natomiast nie jest wymagana bardzo zaawansowana wiedza z zakresu tego języka.
Mam nadzieję, że poprzednia lekcja otworzyła ci oczy na to, jak tak naprawdę działa Node i na czym polega
jego jednowątkowa pętla zdarzeń.
Natomiast wydaje mi się w tym momencie, że być może nie powiedziałem o jej zaletach - z tego powodu, że
pokazałem ci, iż wszystkie połączenia są obsługiwane w jednym wątku. Czyli jeżeli funkcja obsługi zdarzenia
takiego podłączenia - ktoś się podłącza przez HTTP - i jeżeli ta funkcja będzie długotrwała, tak jak u nas
przez tę funkcję sleep, to żadne inne połączenie nie może być zrealizowane.
No i przedstawiłem to w taki sposób, jakby to było minus. Z jednej strony jest to minus, ale tylko wtedy,
kiedy nie wiemy, jak z tego korzystać.
Dlatego że Node specjalnie został stworzony w ten sposób, aby wykorzystać to jako plus.
Plusem jest to, że wszystko to dzieje się w jednym wątku, dlatego w porównaniu np. do serwera Apache i języka
PHP możemy obsłużyć dużo dużo więcej zapytań na sekundę i dlatego Node jest świetny
właśnie do takich serwerów czy HTTP, czy np. serwerów TCP albo WebSocket, z których będziemy jeszcze w tym kursie
korzystać.
Z tego powodu, że nie musimy przydzielać kolejnego wątku na każde połączenie, tylko mamy jeden wątek uruchomiony
i on obsługuje wszystkie połączenia, to możemy to wykonywać dużo, dużo szybciej.
Musimy tylko zadbać o to, aby wykonywać operacje asynchronicznie i w tej funkcji, która przyjmuje połączenie,
nie wykonywać zbyt dużo rzeczy w sposób synchroniczny albo takich rzeczy, które obciążają procesor.
W ten sposób jesteśmy w stanie bardzo wiele zapytań na sekundę obsłużyć i zużywać mało pamięci RAM, bo
nie przydzielamy kolejnych wątków, które też miałyby swoją pamięć RAM dla każdego połączenia.
Skoro zatem będziemy otwieranie plików czy pobieranie jakichś danych z bazy danych delegować do zewnętrznego
API, to nasz główny wątek, w którym jest wykonywany kod JavaScript jednowątkowo, będzie mógł cały czas wykorzystywać
maksymalne zasoby procesora, bo nie będzie musiał po prostu czekać, aż jakiś plik zostanie otwarty i mu zwrócony,
zanim będzie mógł wykonywać kolejny kod.
W ten sposób naprawdę świetnie to wszystko działa, jeżeli chodzi o wydajność. Ale musimy mieć na uwadze
w jaki sposób takie serwery pisać. W tej lekcji chcę ci jednak pokazać, z jakich bloków budulcowych jest
zbudowana platforma Node.js i gdzie to wszystko się odbywa. Dlatego jesteśmy na stronie projektu Node na GitHube.
I gdybyś chciał cały kod źródłowy Node sobie pobrać i skompilować, no to możesz to zrobić, klikając tutaj Clone or download
i np. pobrać jako zip albo sklonować Gitem ten URL.
Nie będziemy tego robić, bo możemy tutaj sobie zerknąć do kodu źródłowego bez żadnego problemu.
Na początek chcę ci powiedzieć to, o czym wspominałem wcześniej, że Node.js jest zbudowany z takich trzech głównych
levelów można powiedzieć, z takich poziomów czy z trzech głównych bloków budulcowych.
Pierwszym z nich na najniższym poziomie są zależności, z których korzysta Node. I je możemy znaleźć tutaj
w katalogu deeps jak dependencies.
Jedną z tych głównych zależności, o której już cały czas mówiliśmy, jest właśnie interpreter języka
JavaScript V8, czyli bez niego Node nie mógłby działać, bo właśnie tutaj będzie przekazywany tekst, czyli
kod JavaScript przez nas pisany, a także napisany wcześniej przez Node - zaraz zobaczysz - i będzie to wykonywane
przez ten interpreter. Dokładnie taki sam interpreter V8 znajduje się na przykład w przeglądarce
Chrome, w której teraz, jak możesz tutaj zauważyć, jesteśmy.
Czyli gdybym przeszedł sobie tutaj do konsoli i w konsoli wykonał jakikolwiek kod, to również V8 będzie go tak
naprawdę obsługiwał. Inną z zależności Node na tym najniższym poziomie jest np. biblioteka zlib, z której
korzystaliśmy, kiedy pokazywałem ci streamy i tworzyliśmy gzipa. Z innych zależności to np. jeszcze
OpenSSL. Służy ta biblioteka do szyfrowania.
Mamy tutaj również npm, z którego będziemy korzystać już w kolejnym rozdziale. Mamy http.parser i
jeszcze kilka innych rzeczy. Natomiast jedną z najważniejszych rzeczy, które tutaj są, jest biblioteka
libuv, którą znajdziesz w tym miejscu. Kliknę tutaj i możemy przejść do jej kodu, którego nie będziemy
analizować, ale zerkniemy sobie na Readme.
I tutaj możesz zobaczyć, co jest napisane. Mianowicie biblioteka libuv napisana w C++ pozwala wykonywać
synchroniczne operacje input output, czyli np. odczytywanie plików.
To jest tak naprawdę sercem Node.js, że możemy odczytywać pliki w sposób asynchroniczny, a za to wszystko
możemy podziękować twórcom biblioteki libuv. Teraz jeden poziom wyżej znajdują się API Node napisane
w języku C++, czyli właśnie dopisane do tych zależności, które widzimy w tym miejscu.
I te API będziesz mógł znaleźć tutaj, w katalogu src. Zaraz sobie do nich wrócimy, bo na najwyższym poziomie
z kolei będziemy mieli API napisane w JavaScript i nazywa się to Node Standard Library.
I to z kolei znajduje się tutaj, w katalogu lib.
No i właśnie może cię zaskoczę, bo ja sam na początku swojej przygody z Node.js myślałem, że to wszystko
jest gdzieś pod spodem napisane tylko w C++, że my piszemy kod JavaScript, ale że sam Node.js takiego kodu
JavaScript nie wykorzystuje.
Okazuje się jednak, że jest inaczej i np. wtedy kiedy używamy funkcji require.fs, czyli inkludowaliśmy sobie
moduł file system, to mógłbyś pomyśleć, że tak naprawdę inkludujemy sobie jakiś moduł napisany w C++ i w
jakiś tam sposób możemy w JavaScript z niego korzystać.
Tak jest, ale tylko po części, dlatego że zauważ, iż mamy tutaj moduł fs.js, czyli w momencie, kiedy robimy
require.fs tak naprawdę ten plik jest dla nas importowany. Ten plik wygląda w ten sposób i zauważ, że on
korzysta tutaj z różnych rzeczy, z których my korzystaliśmy, np. z innych modułów typu path czy util.
Tutaj jednak może się zrodzić kolejne pytanie. Skoro my w naszym kodzie korzystaliśmy z require.fs i np.
odczytywaliśmy plik, a okazuje się, że ten moduł jest napisany w JavaScript, to jakim cudem możemy odczytać
plik, skoro na pewno wiesz, sam język JavaScript nie pozwala na odczytywanie plików.
Czyli silnik V8, który wykonuje nasz język JavaScript, potrafi go wykonywać jakby zgodnie ze specyfikacją,
a w specyfikacji nie ma nic o odczytywaniu plików.
Dlatego aby to wszystko znaleźć, to przypomnijmy sobie metodę, z której korzystaliśmy do odczytywania
plików. Nazywała się readFile.
Spróbuję ją wyszukać w tym module.
Okazuje się, że ona się tutaj znalazła.
Czyli za każdym razem, kiedy my korzystaliśmy z fs.readFile, wykonywaliśmy tę funkcję, przekazując jej ścieżkę,
opcje czy callback.
No właśnie, ale gdzieś po przekazaniu tej ścieżki musi przecież być otwarty plik, a później jego dane
są do nas zwracane.
Dlatego szukajmy dalej.
No i okazuje się, że rzeczywiście gdzieś na dole jest coś takiego jak binding.open.
I wydaje się, że jakby w tym miejscu to wszystko jest przekazywane do świata C++, w którym jest ten plik
otwierany.
No ale znowu rodzi się pytanie, skąd wzięło się binding i aby to znaleźć, przejdziemy na samą górę.
I tutaj znajdziemy po części odpowiedź na nasze pytanie. Mianowicie chociaż w JavaScript będąc, tworzymy
stałą binding, to odwołujemy się do process.binding fs
i to jest ta brama pomiędzy JavaScript a światem C++.
Dokładnie poprzez process.binding. Czyli coś tutaj zostało zwrócone do tego binding i dalej w JavaScript
z tego korzystamy i ten obiekt binding ma taką metodę jak open, która jest wywoływana, kiedy my korzystamy
z read.File.
Oczywiście pytaniom nie ma końca, dlatego jeszcze jeden krok
przejdźmy dalej, aby znaleźć miejsce, w którym taka metoda open znajduje się na tym binding. Przejdziemy
do nowej karty, bo będę chciał ci pokazać, gdzie to jest i do src, następnie do node_file - tutaj taki
plik gdzieś znajdziemy w
C++. Dokładnie to jest ten plik. I to, co jest ważne, to jakby ten plik czy obiekty eksportowane z tego pliku
będą się znajdować w tym miejscu pod binding.
Dokładnie tutaj.
Czyli skoro na tym obiekcie binding, widziałeś niżej, mamy metodę open, to skąd ona się wzięła?
Wyszukajmy jej tutaj - open. Będziemy przeskakiwać. Powiem ci, w którym miejscu ją znajdziemy.
Mianowicie tutaj. Bardzo ważny jest ten blok kodu, który ustawia odpowiednie metody. Czyli tutaj jakby
mówi, że jeżeli z .open skorzystamy tutaj po tej stronie - jeszcze raz sobie readFile wyszukajmy,
jest to tutaj - jeżeli skorzystamy z binding.open, to wywoła tak naprawdę funkcja open, która jest zdefiniowana
w tym pliku.
Zauważ, że mamy tutaj jeszcze inne funkcje. Korzystaliśmy np. z readdir. Czyli znowu - jeżeli tam byśmy skorzystali
z binding.readdir, to wykona się funkcja C++ readdir. Bo teraz jesteśmy w pliku C++. Więc może znajdźmy sobie
tę funkcję open. Wyszukam open i dokładnie w tym miejscu się ona znajduje.
Czyli ta funkcja C++ jest wykonywana zawsze wtedy, kiedy my w Node.js skorzystamy z fs.readFile. Nie będziemy
już wnikać w to, co tutaj się dzieje, ale mam nadzieję, że na tyle rozumiesz różnicę pomiędzy JavaScript a
np. językiem C++, że w JavaScript nie możemy odczytywać plików, ale w C++ już tak.
I znowu - sam silnik V8, który pozwala nam interpretować język JavaScript nie pozwoli nam jakby otwierać plików
domyślnie, bo w JavaScript nie ma takiej funkcji. Ale silnik V8 posiada specjalne API, gdzie możemy sobie dopisać
własne funkcje.
Czyli moglibyśmy dopisać funkcję, mówiąc V8: Jeżeli gdziekolwiek w JavaScript, który będziesz interpretował,
znajdziesz odwołanie do readFile, to wtedy nie zgłaszaj błędu, że readFile is not defined, ale wykonaj tę
naszą funkcję, którą tutaj w C++ sobie napisaliśmy i przekaż do niej te parametry, które w JavaScript ktoś
ci przekazał.
My tutaj w C++ obsłużymy to wszystko, otworzymy sobie plik, bo wiemy, jak to w C++ zrobić i później w odpowiedni
sposób określamy ci te dane i będziesz mógł je później dalej skonsumować w JavaScript.
Więc mam nadzieję, że pod tym względem jest to dla ciebie jasne.
Na koniec chcę ci pokazać jeszcze jedną ciekawostkę odnośnie serwera HTTP.
Gdybyśmy sobie tutaj wrócili do tego głównego katalogu i do lib, to znowu za każdym razem, kiedy importowaliśmy sobie
poprzez require.http,
to nie był jakiś magiczny moduł C++ zwracany,
ale ten plik htttp_server. Ja w tym kursie nie przez przypadek pokazałem ci, że możemy tworzyć serwery na
najniższym poziomie za pomocą takiego modułu Node, który nazywa się net i zauważ, że on w tym miejscu również
się znajduje. On gdzieś pod spodem oczywiście musi mieć taki binding do C++ właśnie z tego powodu, że znowu
w JavaScript domyślnie w specyfikacji nie mamy czegoś takiego jak nawiązywanie połączeń TCP IP.
Ale w C++ mamy już do tego odpowiednie biblioteki. Kawałek niżej mamy właśnie proces binding do tego
HTTPParser, czyli do pliku, który pokazałem ci, że jest jedną z zależności obok np. V8 czy biblioteki libuv
gdzieś tam na najniższym poziomie Node. I przechodząc niżej, zobaczymy, że mamy tutaj listę wszystkich
status kodów serwera HTTP.
Ja przyznam szczerze, że kiedy uczyłem się korzystać z Node, to znowu myślałem, że importując sobie poprzez
require.http taki serwer, wykorzystujemy gdzieś jakieś biblioteki C++ od razu. A tutaj się okazuje, że nie,
że w JavaScript został ten serwer napisany, wykorzystując m.in. moduł net. A to pokazuje nam tylko tyle, że
my wykorzystując moduł net, moglibyśmy sobie teoretycznie w JavaScript napisać pełnoprawny, działający
serwer HTTP. Kończąc tę lekcję, pokażę ci jeszcze tylko, w którym miejscu nasz kod tak naprawdę jest wywoływany,
bo jest to równie ciekawe. Przejdziemy sobie z powrotem do lib, czyli do tych modułów JavaScript i
mamy tutaj taki plik jak module. Gdzieś go powinniśmy tutaj niżej znaleźć.
Jest on w tym miejscu. I wyszukam sobie tutaj czegoś takiego jak makeRequireFunction, bo chcę ci coś pokazać. Mianowicie
że tworzymy tutaj zmienną require,
czyli jest to ta nasza funkcja, która dla nas była przekazywana, a następnie mamy coś takiego jak args.
I być może coś ci to już przypomina, jeżeli na to spojrzysz. Pokazywałem ci w tym kursie, że każdy plik Node,
który my sobie piszemy, mamy go z rozszerzeniem .js,
tak naprawdę jest oplatany jeszcze taką samowywołującą się funkcją, której są przekazywane parametry
kolejno exports, następnie require, żebyśmy z tej funkcji mogli korzystać, potem module, potem filename i dirname.
Zauważ, że dokładnie to są te parametry. One są w tym miejscu i mamy je w args. I one są przekazywane do
tej funkcji
tutaj później poprzez compiledWrapper.apply
i tutaj. Wiem, że to może wyglądać skomplikowanie, ale dokładnie stąd bierze się
file__filename czy dirname, z którego możemy korzystać.
One są w tym miejscu i właśnie tutaj gdzieś wcześniej one są jakby odkrywane. Czyli w tym miejscu gdzieś
jest zapisywane, w jakim jesteśmy pliku, w jakim katalogu, a dopiero później tutaj jest to przekazywane
do naszej funkcji.
Gdybyśmy sobie tak chcieli analizować krok po kroku np. skąd wziął się compiledWrapper, moglibyśmy przejść do
góry i to zobaczyć. To jest z kolei tutaj i znowu - chociaż cały ten plik, w którym teraz jesteśmy, jest
javascriptowy i on musi być wykonywany przez V8,
to okazuje się, że właśnie tutaj dopiero jest jakby wczytywany cały nasz plik, który my napisaliśmy i
dopiero tutaj przekazywany do V8, czyli trochę taka Incepcja.
Natomiast gdybyś sobie przeszedł na stronę nodejs.org - pod tym adresem - czyli po prostu przeszedłem sobie do dokumentacji
i tutaj do vm, to zobaczyłbyś, że my w naszym kodzie możemy sobie w dowolnym miejscu zainkludować taką wirtualną
maszynę V8 i możemy jej w dowolnym momencie przekazać kod do wykonania. Zauważ, że kodem będzie właśnie
taki tekst, czyli kod JavaScript.
Możemy to przekazać i wykonać sobie później, tak jak to może zobaczyć w tym miejscu script.runInContext.
Polecam ci, żebyś sobie z tym poeksperymentował. Ale dokładnie ta sama rzecz dzieje się w tym miejscu jeżeli
byśmy sobie wrócili.
Mianowicie vm.runInThisContext. Jeżeli na tym etapie niewiele ci to mówi, to nie przejmuj się.
Tutaj dzieje się tylko tyle, że pliki, które my piszemy, są to pliki tekstowe. One są przekazywane właśnie do
tego vm i wykonywane w ten sposób. Jest to jakby kompilowane.
Później możemy to wykonać, przekazując tutaj jeszcze odpowiednie argumenty.
Podsumowując zatem, mamy w Node.js wykonywanie JavaScript tylko w jednym wątku, ale cała platforma Node.js
jest wielowątkowa i teraz jeszcze chcę ci to udowodnić.
Przejdę do terminala, uruchomimy interfejs REPL, czyli wpiszę node i teraz przejdę do monitora aktywności
w moim systemie i wyszukam node.
Jeżeli to zrobię, to mamy dokładnie ten proces w tym miejscu.
I zauważ, że tutaj pod kolumną Threads mamy 10.
To oznacza, że ten proces node uruchomił 10 wątków.
Mówiłem ci, że nasz JavaScript będzie zawsze wykonywany w jednym wątku, ale np. otwieranie plików jest wykonywane
w innych wątkach.
Z tego powodu, że mamy tam właśnie te pokazane ci przed momentem w kodzie źródłowym Node moduły odpowiedzialne
np. za otwieranie plików.
Jeżeli do tej wiedzy dołączysz to, o czym mówiłem w lekcji poprzedniej, że wątki współdzielą sobie pamięć, to
będziemy wiedzieć, że możemy tutaj otworzyć sobie jakiś plik w osobnym wątku, kiedy jego treść zostanie
wczytana do pamięci i będziemy chcieli tę treść przekazać do naszego wątku, który wykonuje JavaScript,
to nie musimy tego kopiować tak jak pomiędzy procesami, ale wątki współdzielą ze sobą pamięć, więc wystarczy
że wskaźnik do tej pamięci przekażemy i możemy już coś z tymi danymi robić, tak jak do tej pory robiliśmy
to w tym kursie za każdym razem, gdy korzystaliśmy np. z funkcji readFile.
Gdybyśmy natomiast przeszli do kodu i mielibyśmy taki znajomy nam już serwer, to mówiłem ci, że ta funkcja
będzie się wykonywać dla każdego nowego połączenia.
I zauważ, co tutaj robię na dole.
Otóż każdemu z nich wysyłam counter, który ma wartość 1.
Ale jeżeli którekolwiek połączenie miałoby w swoim stringu, w querystringu coś takiego - czyli napisałbym
tutaj ?value równa się np. 2 - to sobie tutaj sparsowałem - to wtedy zmienną counter ustawię na taką
wartość, czyli np. na 2. Robię to w tym miejscu i 2 zostanie odesłane.
To pokazuje nam tylko tyle, że każde kolejne połączenie jakby jest wykonywane w tym samym wątku. Bo podłączymy
się w jednej przeglądarce, zostanie odesłane 1, potem podłączymy się kolejną przeglądarką właśnie z
takim
querystringiem 2
i każde kolejne połączenie będzie już otrzymywać 2, bo ona tutaj zostanie zmieniona.
Natomiast w przypadku np. języka PHP cały ten plik byłby wykonany dla każdego nowego połączenia.
Czyli nie byłoby takiej sytuacji, że jakieś zmienne mogą być pomiędzy połączeniami współdzielone. Jeżeli
jakimś cudem tymi dwoma lekcjami udało mi się ciebie nie zanudzić, a pokazać ci, w jaki sposób działa Node, to
bardzo się cieszę.
Jeżeli czegoś dokładnie nie zrozumiałeś, to w przyszłości wróć do tych lekcji.
Natomiast teraz będziemy kontynuować poznawanie Node.js i zobaczysz w tym kursie jeszcze wiele ciekawych przykładów,
jak możemy z Node korzystać.