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.
W tej lekcji omówimy bardzo ważną w Node koncepcję, jaką są zdarzenia. Bardzo często możesz usłyszeć, że
w Node.js programujemy w takim stylu, który nazywa się event driven programming, czyli programowanie napędzane
zdarzeniami.
I dokładnie tak jest. W tej lekcji będę chciał ci wytłumaczyć, w jaki sposób to działa i mam nadzieję,
że będzie to dla ciebie coś, co już wcześniej widziałeś,
szczególnie jeżeli pisałeś skrypty w JavaScript dla przeglądarek internetowych. Nasłuchiwanie na zdarzenia
i wywoływanie funkcji callback jest bardzo podobne do tego, co mamy np. w przeglądarce, kiedy przypisujemy
zdarzenie kliknięcia do jakiegoś przycisku. Nie wiemy, kiedy ktoś kliknie w ten przycisk i nie wiemy, czy w ogóle
kliknie w taki przycisk.
Ale jeżeli to zrobi, to my wcześniej już oddelegowaliśmy funkcję, która ma się wówczas wykonać. I podobnie
będzie w Node.
Oczywiście tutaj nie będziemy w nic klikać, ale będziemy mogli przypisać funkcje callback, które mają
się wykonać, kiedy odpowiednie zdarzenie na odpowiednim obiekcie zostanie wyemitowane.
I teraz będę chciał ci pokazać, jak to możemy zrobić. Na stronie dokumentacji
jesteśmy w module events. I teraz sobie go będziemy chcieli zaimportować.
Jest to jeden z wbudowanych modułów Node i pokażę ci, jak z niego korzystać.
Jak widzisz, tutaj mamy opis wszystkich jego metod i nie jest ich zbyt wiele, więc nie jest to moduł skomplikowany.
Dlatego po tej lekcji polecam ci, abyś zapoznał się jeszcze z niektórymi metodami, których ja nie omówię
w tej lekcji.
Widzimy tutaj, że stability: 2 - stable, czyli tutaj nic nie powinno się zmienić. Tutaj na dole widzimy
również, jak to zaimportować, co teraz sobie zrobimy.
A więc w pliku index.js, w katalogu 06, będę chciał utworzyć stałą EventEmitter.
Nazwa ponownie jest dowolna. I tutaj za pomocą znanej nam już funkcji require będziemy chcieli sobie
pobrać events.
Ok.
I teraz to, co jest ważne, to do EventEmittera tutaj zostanie zwrócona funkcja, która jest konstruktorem.
A to oznacza, że będziemy mogli tworzyć nowe obiekty jakby instancji tej klasy za pomocą słowa kluczowego new.
Są to koncepcje programowania obiektowego, które niezwykle dokładnie tłumaczę w kursie JavaScript
w praktyce,
gdybyś jeszcze nie zdążył ich dokładnie poznać. Teraz będziemy chcieli sobie z tej klasy utworzyć nowy
obiekt, więc stworzy zmienną emitter i słowem kluczowym new EventEmitter będziemy chcieli utworzyć sobie
taki obiekt.
Czyli tutaj teraz będziemy mieli obiekt, który ma bardzo wiele różnych metod, właśnie tych, które widzisz w tym
miejscu. I będziemy z nich chcieli teraz skorzystać, abym mógł ci wytłumaczyć, w jaki sposób działają takie
emitery i zdarzenia.
To, co tutaj prezentujemy, nazywane jest również modelem pub/sub, czyli publish/subscribe, a więc możemy
jakby subskrybować pewne zdarzenia, a emiter może je publikować.
W jaki sposób to wygląda?
Otóż wpiszmy sobie emitter.on, czyli jest to bardzo podobne np. do kodu jQuery,
jeżeli kiedykolwiek z tą biblioteką miałeś do czynienia. Chcemy przypisać pewne zdarzenie dla tego emitera
i możemy go nazwać dowolnie, podajemy tutaj string.
Ja napiszę message i podamy funkcję. Chciałbym, żeby ta funkcja przyjmowała sobie parametr msg, który później
tam będzie przekazany. I kiedy go otrzymamy, to będę chciał wyświetlić w konsoli taką oto wiadomość. Napiszemy
"wiadomość" i do tego będę chciał dodać msg.
Czyli tutaj robimy po prostu subskrypcję, czyli mamy obiekt emitera i mówimy, że na zdarzenie o nazwie wiadomość
chcemy wywołać taką oto funkcję i chcemy, żeby ten emiter coś do niej przekazał tutaj pod ten parametr.
I teraz ważne jest to, że możemy do takiego emitera przypisać bardzo wiele różnych zdarzeń o różnych
nazwach lub też kilka zdarzeń o tej samej nazwie. Czyli pod spodem albo w całkowicie innym miejscu w
kodzie,
gdybyśmy to wyeksportowali do jakiegoś modułu, możemy przypisać kolejne zdarzenie o nazwie message i one
będą później wywoływane w tej kolejności, w jakiej zostały przypisane.
Co jest jeszcze bardzo ważne, to domyślnie do takiego emitera możemy przypisać 10 zdarzeń tego samego
typu.
Czyli jeżeli przypisałbym kolejne o nazwie message, to możemy mieć maksymalnie 10 takich zdarzeń, a 11
przypisane zdarzenie zgłosi nam w konsoli, czyli tutaj w tym miejscu, ostrzeżenie o tym, że możemy mieć
potencjalny wyciek pamięci, a to oznacza, że być może przez przypadek przypisaliśmy zbyt wiele zdarzeń. I gdybyśmy
chcieli więcej niż 10 zdarzeń bez ostrzeżenia przypisywać, to możemy tutaj na początku odwołać się do
emitter, w ten sposób, i następnie skorzystać z metody setMaxListeners i możemy tutaj podać wartość,
np. 20. Albo możemy podać 0
i wtedy będzie to wartość nielimitowana.
Ja to tutaj zostawię, ale nie będziemy z tego korzystać.
No i teraz kiedy wywoła się ta funkcja. Sprawdźmy. Przejdziemy sobie tutaj i spróbuję wywołać plik index.
I jak widzimy, nic się nie stało.
Czyli ta funkcja nie wykonała się nigdy, bo ona wykona się, kiedy takie zdarzenie message będzie miało
miejsce.
Ono będzie miało miejsce dopiero wtedy, kiedy emitter wywoła na sobie metodę emit.
i tutaj napiszę message.
To znaczy, że w tym momencie chcemy takie zdarzenie wywołać.
I znowu, porównując to do jQuery, w jQuerty mielibyśmy metodę trigger,
jeżeli jesteś z tym zaznajomiony. I tutaj jako drugi parametr i kolejne może podać parametry, które będą do tej funkcji nasłuchującej
przekazane. Czyli my tutaj chcemy wywołać funkcję, która będzie miała taki parametr message, więc możemy
to podać w tym oto miejscu. Napiszmy tutaj Witaj świecie! i w tym momencie zostaną wywołane wszystkie funkcje,
w tym przypadku jedna, przypisane do tego zdarzenia message.
Możemy to sprawdzić i dokładnie tak się stało.
Jak widzisz, console.log się pojawił.
No i na tym etapie mógłbyś pomyśleć, że niespecjalnie widzisz zastosowanie tego, co tutaj widzimy, ale
już za moment pokażę ci praktyczny przykład, jak możemy dziedziczyć z tej klasy EventEmitter.
Natomiast zanim to zrobię, to chciałbym ci powiedzieć, że ta lekcja jest bardzo ważna, dlatego że tutaj
pokazuję ci koncepcję tego, w jaki sposób działa przypisywanie zdarzeń i ten model pub/sub, natomiast w
Node.js bardzo wiele wbudowanych modułów dziedziczy z tej klasy EventEmitter, dlatego takie przypisywanie
zdarzeń będziemy jeszcze wielokrotnie w tym kursie widzieć i wtedy będziesz rozumiał, skąd to się wzięło.
Ok.
Przejdźmy teraz do bardziej praktycznego przykładu. Będę chciał stworzyć taką pseudoklasę, która będzie
nam pobierać jakby jakieś dane z internetu.
Tych danych nie będzie, ale tak sobie to wyobrazimy.
I za każdym razem, kiedy takie dane mieć będzie, to będziemy chcieli wywołać jakieś zdarzenie czy innymi
słowy wywołać funkcję callback przypisaną wcześniej.
Z tego powodu wykomentujemy sobie jeszcze wszystko, co jest w tym miejscu. I będę chciał utworzyć nowy plik w
katalogu 06 i nazwiemy go puller.js.
Będzie to taka klasa, która tak jak wspomniałem, będzie nam co kilka sekund pobierać coś z internetu i
przekazywać dalej.
I teraz będziemy chcieli tutaj utworzyć sobie konstruktor.
Czyli będzie to nic innego jak funkcja, ale zanim to zrobimy, to podobnie jak tutaj, będę chciał sobie
pobrać EventEmittera.
W ten sposób. Będziemy jeszcze potrzebowali utils. A więc napiszemy util.
To jest też wbudowany moduł Node, który już znasz. I teraz będę chciał utworzyć funkcję, którą nazwiemy Puller.
W ten sposób. Ona tutaj będzie przyjmować pewien adres URL. Zaraz zobaczysz, do czego nam to będzie potrzebne.
I teraz znowu jesteśmy jakby w koncepcji programowania obiektowego.
Wspominałem, że w osobnych kursach na eduweb dokładnie to tłumaczę. Mam nadzieję, że ty to rozumiesz. I teraz
będziemy z takiego Pullera chcieli tworzyć nowe obiekty za pomocą new Puller. Czyli wtedy, kiedy utworzymy
sobie nowy obiekt, to ta klasa jakby jest wywoływana i słowo kluczowe this wewnątrz kieruje na taki nowy
obiekt, który właśnie został utworzony.
Dlatego chcę mu dodać nową właściwość URL i przypisać do niej URL przekazany w tym miejscu. I powiedzmy,
że na razie tyle wystarczy. A teraz będę chciał ci pokazać, w jaki sposób możemy w naszej klasie Puller
dziedziczyć z EventEmittera po to, abyśmy tutaj również mogli przypisywać zdarzenia. W JavaScript dziedziczenie
polega po prostu na odpowiednim ustawieniu prototypów. I mamy fajną metodę, która jest tutaj w klasie
czy w zasadzie w module util, która nam na to pozwala.
Później w konkursie pokażę ci jeszcze, jak zrobić to w inny sposób za pomocą ECMAScript 6.
Ale na razie zrobimy to w taki oto sposób. Więc odwołamy się do utils i następnie inherits. I tutaj musimy
podać jakby naszą klasę, czyli Puller,
i z czego ma ona dziedziczyć, a więc EventEmitter. W ten oto sposób odpowiednio prototypy zostaną ustawione.
Czyli wszystkie metody, które ma EventEmitter, od teraz będzie miała również nasza klasa Puller.
Natomiast aby wszystko odpowiednio działało i aby nowo tworzony obiekt otrzymał odpowiednie właściwości,
tak jak ja sobie tutaj przypisałem np. this i URL, to możesz sobie wyobrazić, że kiedy korzystamy z new EventEmitter,
to tam w środku też podobne rzeczy się dzieją. Aby to zostało zaaplikowane do naszego obiektu,
to skorzystamy sobie z takiego zapisu, mianowicie EventEmitter.call(this). I teraz znowu może to się wydawać
skomplikowane, ale we wspomnianym wcześniej kursie bardzo dokładnie takie rzeczy tłumaczę.
Gdybyś miał jakieś wątpliwości, że w tym kursie nie tłumaczę wszystkiego od zera. Niestety nie jestem
w stanie powtórzyć całego poprzedniego kursu w tym kursie Node, dlatego pewna wiedza jest już zakładana, że
ją posiadasz.
To co do tej pory zrobiliśmy, to oznacza tylko tyle, że możemy tworzyć nowe obiekty Puller w ten sposób
i każdy z takich obiektów będzie dziedziczył z EventEmittera, czyli będziemy mogli do niego przypisywać
zdarzenia tak, jak pokazywałem ci to w tym miejscu, a on będzie mógł emitować również swoje zdarzenia za
pomocą emit.
Dlatego będę chciał teraz z tej funkcji
na samym końcu czy z tego modułu zrobić module.exports i Puller. W ten sposób. I będziemy chcieli cały ten
moduł sobie tutaj zaimportować w tym pliku.
Może zrobimy to tutaj,
z tego samego katalogu puller. OK.
Zostanie nam zwrócona ta oto klasa.
Czyli będziemy mogli sobie utworzyć nowy obiekt. Zrobimy sobie to w tym miejscu za pomocą new.
No i właśnie teraz nowo utworzony obiekt, na który kieruję this,
jest jakby w tym miejscu. Jesteśmy tutaj. Wszystko zostanie ustawione z EventEmittera i później dodamy jeszcze
URL, który przekażemy. Więc w tym momencie chcemy tutaj przekazać jakiś adres URL i podamy sobie tutaj jakiś
fikcyjny adres w internecie.
Powiedzmy, że w ten sposób. Czyli tworzymy sobie nowy obiekt i mówimy, że chcemy, aby dane były z takiego
adresu pobierane. I teraz będziemy chcieli do niego przypisać pewne zdarzenia.
Zrobię tutaj trochę miejsca i teraz będę chciał utworzyć funkcję, którą nazwiemy printData. I ta funkcja
będzie przyjmowała tutaj jakieś dane. Będzie to później obiekt. I będę chciał, aby ona robiła po prostu
console.log i wpiszemy sobie coś takiego. I teraz być może jest to dla ciebie nowość.
To co tutaj wpisałem, nie jest to taki zwykły string, czyli nie są to ani apostrofy, ani cudzysłowy.
Są to takie backticki. I to jest kolejna funkcjonalność ECMAScript 6, która
tutaj w Node działa i nazywa się to template strings.
Polega to na tym, że nie musimy tak jak do tej pory tworzyć jakiegoś stringu i dodawać za pomocą plusa,
czyli konkatenować jakichś danych, ale możemy to robić, wpisując tutaj $, następnie parę słów klamrowych
i w środku dowolne wyrażenie. Czyli tak naprawdę to wszystko tutaj zostanie w odpowiedni sposób połączone, zinterpolowane,
bo tak to się fachowo nazywa, i wyświetlane w konsoli.
Czyli zakładamy, że data to będzie jakiś obiekt, który w sobie będzie zawierał
data i następnie URL, a będzie to ten URL, który tutaj przekazaliśmy. I teraz na naszym Pullerze
wiesz, że dziedziczymy z klasy EventEmitter, a to oznacza, że ma on wszystkie jej metody, takie jak np. on.
Przypiszemy sobie takie zdarzenie jak data, czyli on data. Dowolnie sobie to nazwiemy. Chcemy wywołać funkcję printData.
Mógłbym ją tutaj wpisać anonimowo, ale będzie nam ona jeszcze potrzebna później.
Dlatego stworzyłem ją osobno. Czyli teraz mówimy, że za każdym razem, kiedy Puller wykona emit data i przekaże
jakiś obiekt z informacjami, to chcemy wywołać tę funkcję. I następnie chciałbym tego Pullera uruchomić
za pomocą metody pull, która jeszcze nie istnieje, ale teraz sobie ją stworzymy tutaj. Stworzymy ją oczywiście
na prototypie, czyli odwołamy się do Puller.prototype.pull. I będzie to funkcja. Ta funkcja rozpocznie jakby pobieranie
danych z internetu.
To co jest ważne, to tutaj pod this.url będziemy mieli ten adres, który przekazaliśmy w tym miejscu, bo
zapisałem sobie go tutaj. Czyli on w każdej innej metodzie będzie dostępny. I teraz wstawimy sobie tutaj coś
takiego. Jak widzisz, zapisałem sobie referencje do this tutaj w self tylko po to, żebyśmy wewnątrz funkcji
setInterval, która jest tutaj, mieli odwołanie do tego obiektu, bo tutaj this nie kierowałoby już na ten obiekt.
Takie mamy problemy w JavaScript. I robię sobie tutaj coś takiego, że pod self.interval zapisuję to, co
zwróci nam funkcja setIntervale.
Mam nadzieję, że tę funkcję znasz z przeglądarkowego JavaScript. Ona w Node też jest dostępna i mówimy
tutaj generalnie, że chcę tę funkcję wywołać co sekundę, czyli co sekundę będziemy robić na tym obiekcie,
tak naprawdę na this, emit,
czyli to, co już pokazywałem. Nazwa zdarzenia jest to data. Przypisaliśmy, że tutaj na data chcemy nasłuchiwać
i mamy funkcję printData, która ma przyjąć jakiś obiekt. I ten właśnie obiekt sobie podajemy w tym miejscu.
Czyli data to będzie pobrane dane, a url to będzie ten, który wcześniej pokazaliśmy czy przekazaliśmy,
dlatego to się pojawi w tym miejscu.
Mam nadzieję, że to jest jasne. Czyli po wywołaniu metody pull co sekundę będzie taka funkcja obsługiwana.
Sprawdźmy, w jaki sposób to będzie działać, wywołując sobie node index. No i, jak widzisz, symulujemy sobie pobranie jakichś
danych z internetu co sekundę.
Dzięki temu, że dziedziczymy z EventEmittera, to nigdzie tutaj nie musieliśmy tworzyć nowej klasy new EventEmitter,
ale możemy tworzyć new Puller, tak jak to zrobiliśmy w tym miejscu.
Jak widzisz, wszystko działa poprawnie.
Mam nadzieję, że dobrze to rozumiesz i że ten przykład już pokazuje ci, jak możemy w swoich modułach wykorzystywać
EventEmitter.
Teraz sobie to zatrzymamy za pomocą Ctrl+C. Wyczyszczę ekran i pokażę ci jeszcze kilka ciekawych rzeczy
związanych ze zdarzeniami i z tym modułem events. Wiesz, że co sekundę będziemy sobie takie dane wyświetlać
w nieskończoność, dlatego ja chciałbym tutaj - wywołaliśmy pull i co sekundę te dane są pobierane - zrobić taki
setTimeout i po pięciu sekundach wywołać metodę puller.stop, której jeszcze nie ma - zaraz ją stworzymy -
abyśmy przestali już pobierać te dane i przekażemy jej funkcję, która nam obsługiwała te dane, czyli
printData.
Dlatego ją tutaj zapisałem.
Generalnie będziemy chcieli usunąć zdarzenia, które wcześniej przypisaliśmy, czyli zdarzenia możemy przypisywać
za pomocą on, np. data, a usuwać je możemy za pomocą removeListener. Dodawać również oprócz on możemy
za pomocą addListener.
Jest dokładnie to samo, tylko on jest krótsze, dlatego przejdziemy teraz do naszej klasy i będę chciał
dodać metodę stop.
Tutaj mieliśmy pull, dlatego taki prototyp sobie skopiujemy. I zamiast pull zrobimy stop, a wewnątrz wkleimy inny
kod, który będzie wyglądał tak. Czyli z this, a więc z tego naszego Pullera chcę usunąć zdarzenie data i następnie
usunąć callback, czyli ten callback musimy tutaj przekazać.
Działa to w ten sposób, że jeżeli przypisaliśmy gdzieś funkcję poprzez on, tutaj mamy tę funkcję, to aby ją
odbindować od tego wszystkiego, musimy ją przekazać. Dlatego przekazuję ją do metody stop tutaj.
Ona nam wpadnie w to miejsce pod callback i za pomocą removeListener powiemy, że ma to być event data i
chcemy usunąć tę właśnie funkcję.
Wspomniałem ci jednak, że takich funkcji może być dużo więcej, czyli tutaj może być ich więcej przypisanych.
Ja w tym momencie usuwam tylko jedną z nich. Dlatego zrobimy sobie jeszcze jeden ciekawy trik i będzie
on tutaj na początku w tej klasie Puller.
Ja wkleję gotowy kod. Znowu nie ma tutaj nic skomplikowanego. Zapisuję referencje do this i teraz przypisuję
zdarzenie do naszego Pullera, które nazywa się removeListener.
Ja mówiłem ci, że zdarzenia możesz nazywać dowolnie, np. data, ale jest kilka zdarzeń, które są jakby zarezerwowane.
Jednym z nich jest removeListener. Ono się wykona za każdym razem, gdy usuniemy zdarzenie właśnie w taki sposób.
Czyli teraz jeżeli usuniemy sobie to zdarzenie po wywołaniu stop, to wywoła się inne zdarzenie, które nazywa się
removeListener. I będę chciał sprawdzić, ile jeszcze przypisanych listenerów pozostało. W naszym przypadku
tylko jeden data
przypisaliśmy, więc będzie tylko jeden. Ale gdyby było ich więcej, to możemy to sprawdzić za pomocą this.listenerCount("data").
W ten oto sposób. I po usunięciu takiego zdarzenia za pomocą stop, które mamy tutaj, tu będzie zwrócone
zero. Czyli możemy sobie sprawdzić. Jeżeli numer równa się zero, to wtedy chcemy wyczyścić też ten interval,
który tutaj przypisałem. Bo pamiętaj, że on cały czas będzie co sekundę wywoływał tę funkcję.
Jeżeli my usuniemy zdarzenie data, to nie będzie nasz console.log, który jest tutaj, już się wykonywał, ale za
każdym razem ta funkcja co sekundę i tak będzie wykonywana.
Dlatego w self zapisałem sobie interval, abyśmy za pomocą clearInterval mogli to wyczyścić. Dlatego
zrobimy to w tym miejscu. Tak jak widzisz tutaj. W zasadzie to self
widzę teraz, że nie jest potrzebne. Możemy się tutaj bezpośrednio do this odwołać.
Ok. Więc znowu mam nadzieję, że to jest jasne. Za każdym razem, gdy usuwamy listener, wywoła się ta funkcja
i ona sprawdzi, czy nie ma już innych listenerów. Jeżeli nie, to chcę wyczyścić clearIntervale, podając tutaj
referencje do tego interwału zapisanego wcześniej. Więc możemy sobie teraz sprawdzić, jak to będzie działać.
Więc pamiętaj. że po pięciu sekundach ten setTimeout powinien nam zatrzymać całą naszą funkcję, która
nam pobiera dane z internetu. Więc zróbmy sobie node index. Widzimy, że te dane są pobierane co sekundę
i następnie to wszystko zostało zatrzymane i proces się zakończył, jeżeli chodzi o node, dlatego, że nie
ma już tutaj nic innego do wykonania.
Tak jak wspomniałem, polecam ci, abyś sobie zerknął jeszcze na inne metody, których tutaj nie pokazałem.
Ale mam nadzieję również, że zrozumiałeś dobrze, jak możemy dziedziczyć sobie z EventEmitterta we własnych
klasach.
Czyli możemy tworzyć własne klasy, one tutaj mogą robić najróżniejsze rzeczy, które jeszcze poznasz w tym
kursie i mogą one wywoływać zdarzenia, a także bezpośrednio na nich, tak jak tutaj na tym Pullerze, możemy na zdarzenia
nasłuchiwać. W tym kursie jeszcze wielokrotnie będziemy korzystać np. z on, i z różnych zdarzeń, które będą
na innych wbudowanych modułach Node.js dostępne, dlatego że wiele z tych modułów dziedziczy z EventEmittera.