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 pokażę ci, w jaki sposób radzić sobie z usuwaniem plików i katalogów.
Stworzymy również praktyczny przykład, tak jak w lekcji poprzedniej.
Będzie to funkcja, która pozwoli usunąć cały katalog i wszystkie pliki, które są w nim zawarte.
Pokażę ci dwie metody.
Jedna z nich jest rmdir, którą możesz znaleźć w dokumentacji tutaj. Ma ona również, pamiętaj, swój odpowiednik
synchroniczny.
I ta metoda znowu odpowiada temu, o czym mówiliśmy wcześniej. A więc w systemach UNIX mamy taką
metodę rmdir. Mogę w terminalu za pomocą tej metody usuwać katalogi i w Node.js również ona się znalazła.
A druga z nich do usuwania plików nazywa się unlink.
I teraz wróćmy do edytora i będę chciał ci pokazać, jak one działają.
Mamy katalog files, w którym znajdują się trzy pliki i chciałbym cały ten katalog usunąć.
Natomiast zanim to zrobimy, to chciałbym go jeszcze zduplikować, bo będziemy kilkukrotnie sobie nad tym pracować.
Nazwiemy go files_copy. Ok.
W ten sposób będziemy mieli wszystkie pliki wewnątrz i teraz metodą rmdir pokażę ci, jak ten katalog
możemy usunąć.
Więc fs.rmdir,
no i tutaj podajemy ścieżkę do tego katalogu.
Skorzystamy z path.join.
Podamy dirname i następnie files.
Więc mówię, że chcę usunąć katalog files i podajemy funkcję callback, która się wykona później. Ona przyjmuje
znowu error.
Czyli jeżeli był błąd, to tutaj on będzie. Jeżeli nie, to wartość null.
No i cóż?
Sprawdźmy sobie
za pomocą if(err). To standardowo go wyświetla w ten oto sposób. I teraz sobie ten plik wywołamy, oczywiście
w terminalu - node index.
I zauważ, że wystąpił błąd. I błąd nazywa się w ten sposób: ENOTEMPTY.
Taki błąd pojawi się zawsze, jeżeli będziemy chcieli usunąć katalog, który nie jest pusty.
I co jest ciekawe, ale może wydaje ci się trochę nieintuicyjne, nie możemy za pomocą metody rmdir usunąć
katalogu, w którym znajdują się jakieś pliki.
Nie jest to po prostu możliwe.
Czyli ta metoda pozwala usuwać wyłącznie katalogi, które są puste.
Jeżeli zatem będziemy chcieli usunąć ten katalog, to musimy najpierw usunąć wszystkie pliki, które są
wewnątrz za pomocą metody unlink, a dopiero później możemy usunąć ten katalog i wtedy zapewniam cię,
to się uda i znajdziemy się w tym miejscu, w bloku else.
Dlatego teraz nie będę ci już pokazywał metody unlink, czyli jak za jej pomocą usunąć taki pojedynczy
plik, tylko od razu przejdziemy sobie do stworzenia swojego własnego modułu.
W zasadzie będzie to funkcja, która pozwoli nam wyczyścić cały katalog ze wszystkich plików i w jej wnętrzu
dopiero skorzystamy z metody unlink. Zrobię trochę miejsca i przejdźmy do najpierw wywołania sobie tej
funkcji, tak jak w lekcji poprzedniej.
Łatwiej jest najpierw zapisać, w jaki sposób chciałbyś wywoływać tę funkcję, bo wtedy łatwiej stworzyć
całe jej ciało.
Wkleję zatem, jak chciałbym ją wywoływać. Zatem chciałbym, aby ona nazywała się rmdir.
Możemy sobie tak funkcję nazywać. Tutaj podam katalog, który chcę usunąć. On będzie względnie miejsca,
w którym się znajdujemy, czyli ze ścieżką tutaj popracujemy. I następnie chciałbym sobie podać funkcję, która
będzie funkcją error-first callback.
A więc jeżeli będzie błąd, to chciałbym go mieć pod pierwszym parametrem - również to już znasz.
Jeżeli nie, to tutaj będzie null, a pod dirname chcę mieć nazwę właśnie tego katalogu, który usuwamy, który
tutaj przekazałem, bo chciałbym sobie móc wyświetlić właśnie taki console.log.
Zatem stwórzmy sobie funkcję, którą nazwiemy rmdir i ona przyjmie właśnie nazwę tego katalogu, czyli dir
i callback do wykonania.
Ja teraz będę tutaj wklejał po kawałku
kod tej funkcji. Najpierw chcielibyśmy mieć poprawną ścieżkę, czyli ktoś podał files, ale my wiemy, że musimy sobie
ją odpowiednio jeszcze tutaj sformatować. Skorzystamy z path.join, czyli stworzę sobie tutaj zmienną, którą nazwę dirname = path.join(_ _dirname, dir).
Czyli teraz mamy już poprawną ścieżkę, którą możemy przekazać do funkcji czy do metody rmdir.
Dlatego teraz sobie skorzystamy właśnie z takiego rmdir, jak mamy tutaj.
Będzie to wyglądać w ten sposób. Czyli tutaj już mówimy "Usuń ten katalog" i przekazuję mu dirname, a więc
już poprawną ścieżkę.
Jeżeli uda się usunąć, to będziemy w tym miejscu. Więc co chcemy zrobić, jeżeli katalog udało się usunąć?
No, nic innego jak wywołać naszą funkcję callback, którą mamy pod cb z wartością null.
Bo nie było błędów, więc pod err będziemy mieli null i następnie chcemy ten katalog przekazać, czyli
nazwę tego katalogu, a ją mamy cały czas tutaj pod dir.
Czyli gdybym przekazał dirname, to byłaby to cała ścieżka, a ja chcę przekazać całą nazwę, dlatego tutaj nową
zmienną utworzyłem w ten sposób. Czyli mamy już obsłużony
ten wyjątek, w zasadzie jakby taką sytuację. Czyli jeżeli skorzystamy z naszej funkcji rmdir i katalog files
uda się usunąć, to nam się wykona ten oto kod.
Natomiast dużo bardziej skomplikowana rzecz będzie tutaj. Jeżeli katalog, jak widziałeś już do tej pory,
nie jest pusty, to pojawi nam się błąd, który wygląda w taki oto sposób. I jego err.code będzie wyglądało tak.
Już ci wcześniej mówiłem, że warto robić console.log błędów, aby zobaczyć, jaki jest ich kod.
Czyli jeżeli będzie błąd, to chcę sprawdzić, czy ten błąd wynika z tego, iż katalog nie jest pusty.
Mogą to być inne błędy, ale nas interesuje ten szczególny przypadek.
Czyli możemy odwołać się do err.code i zobaczyć, czy ma on taką wartość jak tutaj.
Jeżeli tak, to znaczy, że nie udało się go usunąć, bo były w nim jakieś pliki.
I to nas interesuje, dlatego obsłużymy to w ten sposób.
Czyli jeżeli error code był inny niż ten, o którym właśnie mówimy, to chcę wywołać naszą funkcję callback, zakończyć
to wszystko poprzez return i przekażemy jej error oraz dirname.
Czyli jeżeli np. nie mieliśmy uprawnień do tego katalogu, to również nasza funkcja callback się wykona i tutaj
będzie odpowiedni błąd.
Natomiast jeżeli katalog nie był pusty, to będziemy chcieli przejść dalej.
A więc w tym miejscu się znajdziemy. I teraz będziemy chcieli znanymi nam już z tego kursu metodami odczytać
wszystkie pliki, które znajdują się w takim katalogu,
każdy z nich po kolei usunąć i dopiero wtedy wywołać funkcję callback już bez błędu. Pozwolę sobie wkleić
cały gotowy kod i szybko ci go wytłumaczę. Jeżeli czegoś nie będziesz rozumiał, to linijka po linijce sobie
go przeanalizuj i przetestuj u siebie.
Tak to wygląda i na pierwszy rzut oka być może wygląda to na proces skomplikowany, ale chcę ci go teraz
wytłumaczyć.
Na początek tworzę zmienną counter - ma wartość 0. I ją będę chciał zwiększać za każdym razem, kiedy uda się
usunąć jakiś plik.
No bo tak: mamy katalog files z kilkoma plikami.
Nikt nie powiedział, że każdy z nich uda się usunąć. Być może się nie uda. Jeżeli któregoś z nich nie uda
się usunąć, to chcę naszą funkcję, którą mamy tutaj, wywołać z błędem. Bo w tej funkcji powiedzieliśmy, że
chcemy usunąć cały katalog.
Ale jeżeli któregokolwiek z tych plików nie uda się usunąć, to i katalogu się nie uda usunąć.
Dlatego będziemy ją zwiększać.
Co robimy
na początek jednak? Otóż znaną tobie już również metodą readdir chcę odczytać wszystkie pliki znajdujące
się w katalogu files. Czyli podaję sobie tutaj dirname, bo mamy to już w zmiennej i wykonujemy kolejną funkcję
asynchroniczną.
Jeżeli nam się nie uda odczytać zawartości tego katalogu z jakiegoś powodu, to chcę zakończyć to wszystko
i wywołać nasz callback
właśnie z tym błędem.
Czyli to, co jest tobie już znane.
Ten callback się wykona, jeżeli się nie uda odczytać tego katalogu.
Jeżeli się uda, przejdziemy sobie poniżej.
I właśnie tutaj znajduje się ta zmienna counter.
Teraz skoro się udało to wszystko odczytać, to będziemy mieli pod files tablicę z nazwami tych plików.
Będą to te trzy pliki. I teraz chcę dla każdego z tych elementów tablicy wykonać taką oto funkcję, która
przyjmie nazwę tego pliku i index. Czyli w index będziemy mieli 0, 1, 2.
Bo po prostu jest to iteracja po tablicy za pomocą metody JavaScript forEach. Czyli teraz tutaj,
w tym miejscu, pod fail mamy nazwę np. lorem1.txt.
Znowu - teraz będziemy chcieli usunąć taki plik metodą, o której ci wspominałem, czyli unlink.
Ta metoda działa w ten sposób, że podajemy ścieżkę do takiego pliku i funkcję callback z błędem,
jeżeli taki błąd wystąpi. Czyli pierwsza z funkcji w tej lekcji, którą ci chciałem pokazać, to jest rmdir
do usuwania katalogów.
A druga to właśnie unlink do usuwania plików, czyli taki plik spróbujemy sobie usunąć.
I teraz bardzo ważna rzecz dzieje się tutaj.
Jeżeli tego pliku nie uda się usunąć, to będziemy mieli błąd.
Czyli nigdy counter się nie zwiększy.
Mamy tutaj wartość zero. Czyli po przejściu dalej będziemy mieli tutaj dalej wartość zero.
Jeżeli natomiast taki plik lorem1 uda się usunąć, nie będzie błędu, to counter się zwiększy.
Czyli po wykonaniu się forEach pierwszej iteracji, czyli tej funkcji, tutaj będzie wartość 1.
Teraz zauważ, co sprawdzam pod spodem. Pod index wspomniałem ci, że mamy poszczególne indeksy, czyli 0, 1, 2
dla tych funkcji.
Chcę sobie sprawdzić, czy indeks +1 jest równy ilości wszystkich plików. Bo jeżeli będziemy już przy końcu,
czyli przy ostatnim pliku, to ma on indeks 2,
bo pamiętaj: 0, 1, 2, czyli 2+1 to jest 3.
Sprawdzimy, czy 3 równa się files.length, czyli ilości tych plików.
Jeżeli 3 = 3, to oznacza tylko tyle, że jesteśmy już przy ostatniej iteracji tej pętli,
czyli przy ostatnim pliku.
To jest pierwszy warunek. A drugi jest taki, czy counter nie jest równy files.length. Czyli jeżeli nie wystąpi
żaden błąd, to za każdym razem zwiększymy counter o 1.
To tutaj powinna być wartość 3.
Zatem ten warunek się nie wykona. Bo counter będzie równy files.length w ten sposób.
Natomiast jeżeli nie udało się usunąć przynajmniej jednego pliku, to counter się nie zwiększył i skoro
tutaj sprawdzamy, że jesteśmy już przy ostatnim pliku, a counter nie ma wartości 3, to znaczy, że nie udało
się któregoś z plików usunąć.
I wtedy chcę zwrócić nasz callback, czyli zakończyć tę funkcję i nasz callback wywołać z nowym błędem.
Tworzę go poprzez new error i wpisuję jego właściwość message. W ten sposób w JavaScript tworzymy nowe
instancje błędów. I jest napisane: "Nie wszystkie pliki udało się usunąć". W ten sposób wywoła się ta funkcja i pod err
będzie ten właśnie new error.
Mam nadzieję, że to rozumiesz, na spokojnie sobie to przeanalizuj.
Czyli jak jesteśmy przy ostatniej iteracji, a counter nie ma takiej wartości jak ilość plików, to znaczy,
że któregoś nie udało się usunąć.
Jeżeli natomiast udało się usunąć wszystkie te pliki, to ten return się nie wykona, a więc będziemy w
tym miejscu. Sprawdzimy, czy counter ma wartość taką jak ilość plików.
Jeżeli counter będzie miał wartość 3. Ilość plików to 3.
To oznacza, że wszystkie pliki udało się usunąć. I wtedy chcę również zakończyć, ale od nowa wywołać tę
funkcję rmdir,
podając jej katalog.
I to może ci się wydawać dziwne.
Dlaczego kiedy
udało mi się usunąć wszystkie te pliki, to raz jeszcze wykonuję funkcję rmdir i przekazuję jej
katalog files.
Otóż chcę ci przypomnieć, co ta funkcja robiła na początku.
Otóż ona próbowała usunąć katalog. Jeżeli się go nie udało usunąć, bo były w nim jakieś pliki, to mieliśmy
cały ten blok.
Natomiast jeżeli wszystkie pliki już usunęliśmy i od nowa wywołam tę funkcję, przekazując jej katalog,
to ona w tym miejscu poprzez rmdir będzie próbowała usunąć ten katalog.
Nie wystąpił błąd, bo on jest pusty, a więc przejdziemy sobie w to miejsce.
Katalog zostanie usunięty i funkcja callback, czyli ta, która znajduje się tutaj, wykona się. Pod error
będzie null,
czyli przejdziemy sobie do tego miejsca.
Wiem, że to może wydaje się skomplikowane, ale jestem przekonany, że na spokojnie jesteś w stanie sobie
to rozkminić.
Ok. Zapiszmy i przetestujmy, a więc raz jeszcze upewnijmy się - jest katalog files, mamy tam trzy pliki.
I tutaj mówię: "Usuń katalog files". Znowu my jako użytkownicy tej funkcji wiedzielibyśmy tylko, że tak się
z niej korzysta.
Nie widzimy tego modułu, wykonajmy sobie node index. Usunięto katalog files, wszystko się udało zrobić - ten
katalog został usunięty.
Natomiast co gdyby któregoś z tych plików nie udało się usunąć?
Przetestujmy to. Jeszcze raz sobie to
zduplikuję. Nazwę go znowu files, a więc mamy znowu katalog z trzema plikami.
I teraz jak możemy zrobić tak, aby nam się któregoś pliku nie udało usunąć?
Wyobraź sobie, że np. pliku lorem2 nie da się usunąć. W tym miejscu pojawi nam się błąd. Counter się nie zwiększy
i będziemy w tym miejscu przy ostatniej iteracji.
Jak ja mogę zrobić tak, aby ten plik lorem2 był nieusuwalny?
Otóż w systemach unixowych mogę skorzystać z takiego polecenia.
Zobaczmy, co tutaj mamy - katalog files. Wpiszę teraz takie polecenie. W Windowsie to polecenie nie
zadziała, ale tutaj, na Macu i na Linux również powinno działać. Zmienię sobie flagę dla pliku Lorem2.txt
w ten sposób, że on będzie nieusuwalny.
Zobaczmy. Teraz spróbujemy raz jeszcze sobie wywołać node index.
I widzisz - wystąpił błąd.
Nie wszystkie pliki udało się usunąć.
Czyli to jest dokładnie to, o czym mówiłem.
Ale zauważ, że nasz moduł jest na tyle dobrze napisany, że radzi sobie ze wszystkimi tymi przypadkami,
a użytkownik końcowy po prostu wykonuje funkcję rmdir, mówiąc: "Usuń katalog files, jeżeli coś pójdzie
nie tak lub wszystko się uda, wykonaj tę funkcję, przekazując jej error lub też nie".
W tym przypadku znaleźliśmy się w tym miejscu, bo jednego z tych plików nie udało się usunąć.
Mam nadzieję, że ten przykład był dla ciebie ciekawy.
Widzisz, jak możemy tworzyć dobry kod z użyciem Node.js, natomiast z tej lekcji zapamiętaj, że mamy dwie metody:
rmdir do usuwania katalogów, które są puste, a unlink do usuwania plików. Nie możemy usunąć katalogu, który nie
jest pusty.
Więc najpierw musimy go wyczyścić z wszystkich plików, a dopiero potem spróbować go usunąć.