Nowy Standard JavaScript
10 godz. 43 min · JavaScript · Full-stack i Programowanie
Piotr PalarzWeb DeveloperNa początku dowiesz się jakie nowości pojawiły się w języku, jeśli chodzi o tworzenie zmiennych i stałych. Poznasz dwa nowe słowa let i const, a także dokładnie omówimy ich różnice, względem znanego nam do tej pory słowa var. Następnie poruszymy temat obiektów. Zobaczysz jak nowy zapis pozwoli znaczenie ułatwić nam pracę i sprawić, by kod był bardziej czytelny. W kolejnym rozdziale porozmawiamy o zmianach w funkcjach. Poznasz tzw. arrow functions wraz z poradami, kiedy z nich korzystać, a także z konsekwencjami ich użycia. Zobaczysz również, jak korzystać z domyślnych parametrów. Następną nowością będą operatory rest i spread, które znacząco uproszczą pisanie kodu dla funkcji i tablic. Chwilę później rzucimy okiem na bardzo ciekawy temat, mianowicie na tzw. destructuring. To nowa funkcja języka, która pozwala w łatwy sposób wyciągnąć odpowiednie dane z tablic i obiektów, nawet jeżeli te posiadają kilkupoziomową, zagnieżdżoną strukturę. Zmian doczekały się również ciągi znaków. Poznasz nowy zapis, tzw. template string, a także możliwość wykorzystania funkcji tagujących.
ES6 wprowadza do języka JavaScript zapis klas. I choć na początku wydaje się, że to duży krok w stronę klasycznych obiektowych języków programowania, to jak się przekonasz, jest to w dużej mierze tzw. syntactic sugar, a więc zupełnie nowy, prostszy zapis, a prawie identyczne jak wcześniej działanie, oparte na dziedziczeniu prototypowym. W kursie poruszymy również temat Symboli oraz tego jak z nimi pracować, a chwilę później poznasz iteratory. To konstrukcje ułatwiające iterację, które znacząco upraszczają pracę z kolekcjami danych. Wraz z iteratorami poznasz również generatory, które ułatwiają z kolei tworzenie tych iteratorów. Istotną nowością w ES6 są również natywne Promise. To sposób na rozwiązanie problemu asynchroniczności, który znamy od bardzo dawna w postaci różnych bibliotek. Od teraz jednak Promisy znajdują się bezpośrednio w języku. Nowymi konstrukcjami, które pozwalają pracować z kolekcjami danych, są Map i Set. Dowiesz się jak z nich korzystać, a także do czego są przydatne. W jednym z rozdziałów rzucimy też okiem na tzw. Proxy API. To mechanizm języka, który pozwala na dość niskopoziomowy dostęp do różnych operacji. I choć być może nie jest to coś, z czego będziesz korzystał nad wyraz często, to warto wiedzieć, jakie są nowe możliwości tego API.
Jedną z najlepszych nowości, która zawitała do języka JavaScript wraz z ES6 są moduły. To możliwość dzielenia kodu na wiele plików, z których można pewne wartości wyeksportować, a następnie zaimportować je w innych modułach. Tutaj dowiesz się wszystkiego, co z modułami związane. Zobaczysz wiele sposobów na eksport i import, a także jak pracować z modułami w przeglądarkach internetowych. Kurs skupia się na omówieniu wszystkich najważniejszych nowości w ES6, dzieląc je na rozdziały. Jeden z nich natomiast, poświęcony został omówieniu mniejszych zmian, które znalazły się w specyfikacji. Poznasz w nim np. nowe metody tablic czy ulepszoną współpracę z Unicode.
Specyfikacja EcmaScript 2015 wprowadziła naprawdę bardzo wiele zmian, ale jej twórcy założyli, że od tego czasu każda kolejna wersja specyfikacji będzie pojawiać się co roku. Oznacza to przede wszystkim, że nie będziemy na raz bombardowani aż tak wieloma zmianami, jak w 2015 roku. W tym kursie nie zabrakło zatem omówienia nowości ze specyfikacji ES2016 oraz 2017, gdzie poznasz np. nowe metody dla stringów czy funkcje asynchroniczne.
Kiedy będziesz już uzbrojony w solidną wiedzę z zakresu nowości w ES6, dowiesz się jak w praktyce pracuje się dzisiaj z tym standardem. W jednym z rozdziałów omówimy nowoczesny workflow z użyciem npm i wykorzystamy popularne narzędzie webpack, do pracy z modułami, a także do transpilowania kodu ES6 do wersji ES5. Dzięki temu nowoczesny kod, który napiszemy, będzie mógł być uruchamiany również w starszych przeglądarkach, które nie wspierają najnowszego standardu. Dowiesz się na co zwrócić uwagę, by wszystko działało bez zarzutu.
Zwieńczeniem tego kursu będzie praktyczny projekt, w którym od podstaw wykonamy swoją własną bibliotekę do pracy z Obiektowym Modelem Dokumentu. Będzie ona w działaniu nieco podobna do znanej chyba wszystkim biblioteki jQuery. Na tym przykładzie postaramy się wykorzystać jak najwięcej wiedzy z zakresu ES6 zdobytej wcześniej. Stworzymy metody do pracy z drzewem dokumentu, a więc do wyszukiwania elementów, do tworzenia nowych, do przypisywania im klas, atrybutów czy styli CSS. Nie zabraknie również modułu odpowiedzialnego za współpracę z Ajax. Cały kod utworzymy oczywiście w sposób modułowy, aby bibliotekę można było łatwo rozwijać w przyszłości. Na koniec projekt ten przetranspilujemy do kodu ES5 z użyciem Babel i przetestujemy w starszej przeglądarce Internet Explorer 11, aby upewnić się, że nasza biblioteka działa poprawnie.
Kurs ten jest dla wszystkich osób, które znają już język JavaScript i czują się w pracy z nim swobodnie. Jeśli zatem chciałbyś pracować z nowoczesnym kodem JavaScript, to ten kurs jest zdecydowanie dla Ciebie. A może masz zamiar poznać framework Angular lub bibliotekę React? Tam również wykorzystywany jest najnowszy zapis ES6, więc wiedza ta będzie naprawdę pomocna. Z solidną wiedzą z zakresu EcmaScript 6, bez trudu pozostaniesz na bieżąco z każdą kolejną edycją tej specyfikacji.
W tej lekcji pokażę ci jeszcze dwie metody statyczne na klasie promise. Jest to all oraz
race i zobaczysz jak można z nimi pracować. Generalnie one pozwalają pracować
na wielu promise'ach jednocześnie, więc mamy tutaj ten sam kod, który wcześniej get json
i chciałbym po kliknięciu w przycisk wykonać sobie kilka zapytań Ajax. Więc
napiszę promise all i tutaj musimy podać tablice albo
dowolny iterable, czyli coś co ma w sobie iterator, ale tablica ma, więc
nie ma żadnego problemu i zazwyczaj będzie to tablica i w tej tablicy możemy podać dowolną
liczbę promise, więc get json jeśli pamiętasz, czyli nasza funkcja get json
ona zwraca promise, więc jeżeli ją wywołamy no to tutaj podstawiamy bezpośrednio promise
i chciałbym teraz tutaj wstawić sobie get json z takim
adresem jak mieliśmy wcześniej z parametrem shuffle 1 żeby te dane były pomieszane i po
przecinku postawię sobie drugą taką linijkę, a więc w konsekwencji
wywołując tą funkcję podstawiamy tutaj dwie promiski i teraz do tego
promise all będę mógł przypisać sobie handler'y, tak robiliśmy to już wcześniej, czyli napiszmy
sobie then. Kiedy wszystko będzie okej, będę chciał mieć pod zmienną data coś.
No właśnie i co to będzie. Okazuje się, że w tym przypadku będzie to tablica, w
której będziemy mieli wyniki tych dwóch promise. Natomiast promise all wykona
się tylko wtedy, czyli then wykona się tylko wtedy, jeżeli obydwie
będą miały status resolve, czyli nie będzie tam żadnego błędu, a więc innymi
słowy, w ogóle ten kod jakby poczeka na to aż uda się
pobrać jeden zasób serwera i drugi. Generalnie w tym przypadku jest
to zasób serwera, ale chodzi generalnie o to, że ma to być funkcja resolve wykonana
i to co ona zwróci z pierwszej promise będziemy mieli w data zero,
bo będzie to tablica, a to co z drugiej będzie w data 1. Jeżeli wiem, że są tutaj dwie
promiski, to wiem, że będą dwa elementy tablicy. Dlatego tą funkcję
sobie zapiszę tak, żeby była trochę bardziej czytelna, a na stronie wyszukamy sobie elementu pre-42
i za jego pomocą będziemy chcieli na stronie wyświetlić to,
co zostanie nam zwrócone. Zróbmy to w formie takiego template string'u i wyświetlimy najpierw
to co będzie pod data 0. Czyli to co z pierwszej promise jakby zwrócone. Następnie postawię
sobie dwa znaki nowego wiersza i zrobimy sobie data 1,
ale żeby jeszcze jakoś rozdzielić, to pomiędzy może zróbmy
sobie coś takiego, że postawimy na takie wyrażenie w
tym template string'u, gdzie będzie równa się i metodą repeat, którą już ci pokazywałem
powtórz mnie to sobie może 70 razy i dodajmy jeszcze dwa
znaki nowego wiersza. Dziwnie wygląda, ale to nam fajnie wszystko sformatuje, więc
sprawdzimy teraz czy to zadziała. Pobierz dane. Widzimy, że się udało. Dwa zapytania
zostały wysłane i gdzieś pomiędzy tutaj powinno to być rozdzielone. Jak widzisz, właśnie siedemdziesięcioma
znakami równa się i mam wynik dwóch promise. Ważne jest jednak to,
że jeżeli jedna z nich miała by status rejected, byłby jakiś błąd, to wtedy od
razu wykona nam się blok catch, który moglibyśmy mieć w tym miejscu. Jeżeli
pierwsza będzie miała rejected, to na drugą nawet nie będziemy czekać. Od razu jakby skoczymy
do catch. Dlatego tutaj wstawię sobie taki fragment, który już
wcześniej widzieliśmy, czyli funkcja arrow, która
wyświetli error message, więc zróbmy sobie błąd tutaj w jednej z nich w adresie. Spróbujmy
wysłać. Pobierz dane i mamy wystąpił błąd. Pamiętaj jednak, że ten
błąd zależy od nas. To ja powiedziałem kiedy ma być zrobione reject. Na podstawie
błędu Ajax'a wcale nie musiałbym tutaj tego robić. Teraz pokażę
ci drugą metodę, która pozwala pracować na wielu promise'ach i jest to metoda race. Na
początku ona się wydaje mało przydatna, ale ja pokażę ci praktyczny przykład. Wpiszemy
sobie promise race i podobnie jak w all podajemy jakiś iterable, który
zawiera w sobie kilka promise. Więc będę chciał tutaj zrobić dokładnie to
samo co wyżej, erase polega na tym, że jakby te dwie promise'y
się ścigają ze sobą. Która się zakończy pierwsza, tej wynik zostanie nam zwrócony
do then. Więc jeżeli tutaj zrobimy then będę miał powiedzmy jakiś
json i chciałbym na stronie móc go wyświetlić w taki sposób. No i
mógłbyś zapytać po co mi tak naprawdę dwie promiski, które się ścigają. Zaraz
ci pokażę praktyczny przykład, ale jeszcze tylko wspomnę o tym, że która z nich skończy pierwsza, to
ta będzie tutaj. No i od razu jakby już nie czekamy zupełnie na wynik drugiej. Okej,
zobaczmy. Pobierz dane. No i pierwsza się
zakończyła i od razu mamy jej wynik. Natomiast ważne jest również to, że podobnie
będzie z catch. Jeżeli tutaj przypiszemy sobie catch, zróbmy
to samo, co wcześniej, bo jeżeli któraś będzie miała błąd,
to na tą drugą już nie będziemy czekać. Zobaczmy. Wystąpił
błąd, czyli to oznacza, że jak pierwsza ma błąd to wyścig jest zakończony, bo
tutaj nie mówimy, że czekamy, która pierwsza zrobi resolve, tylko
czekamy, która pierwsza zrobi resolve albo reject, okej i
teraz pokażę ci praktyczniejszy przykład, bo owszem, jeżeli gdzieś w swoim projekcie
jakimś będziesz wiedział, że są jakieś dane i zależy ci, że albo jedne mają być pobrane
albo drugie i które szybciej, to będziesz o tym pamiętał, natomiast takim praktycznym przykładem
może być tutaj stworzenie timeout'u. No i teraz będę chciał ci to pokazać. Skopiuję
sobie to wszystko i wykomentuje i tutaj podstawimy sobie promise,
czyli mówię pobierz mi takie oto dane, ale jako drugi promise chcę podstawić
inną promiskę zupełnie, która będzie zwrócona z funkcji timeout, którą sobie
utworzymy. Ta funkcja przyjmie parametr 500 i coś mi tutaj zwróci. Ma tutaj
zwrócić promise, bo to muszę podać do tej tablicy. Więc utwórzmy sobie taką funkcję
timeout. Zaraz się to wyjaśni. Jako parametr przyjmie czas
w milisekundach. Podałem tutaj 500. Wewnątrz będziemy chcieli
utworzyć nową promise. Nie muszę jej robić do zmiennej p, tak jak robiłem wcześniej. Mogę
ją od razu zwrócić new promise. Pamiętasz, że promise
przyjmuje funkcję, która będzie miał będzie miała resolve i reject i tutaj
sobie ustawię timeout. Zrobimy settimeout, jest to funkcja, która
pozwoli mi po jakimś czasie coś wykonać i tutaj podaję funkcję, zaraz ją uzupełnię,
a tutaj czas, czyli czas to będzie 500 milisekund, a więc mówię wykonaj
mi coś po 500 milisekundach. Tutaj będzie zwrócona promise, bo zrobiłem return new promise,
nie ma problemu, ale wewnątrz tej funkcji po 500 milisekundach chciałbym
wykonać funkcję, która zrobi mi reject
i przekaże tam nowy obiekt błędu, czyli new
error i napiszemy sobie tutaj, że czas
i tutaj podstawmy dynamicznie ms, ms,
czyli czas na przykład 500 ms. Został przekroczony, okej.
Mam nadzieję, że ma to dla ciebie sens. Wykonamy to sobie i wytłumaczę ci raz jeszcze jak
działa. Pobierzemy i wszystko jest okej, ale jeżeli ustawię tutaj wartość na
10, czyli 10 milisekund. Nagle się okaże, że czas
10 milisekund został przekroczony, czyli za pomocą takiego race i dwóch różnych promise
mogę tutaj powiedzieć pobierz mi te dane, ale nie będę czekał więcej niż
10 milisekund na takie dane. Natomiast jeżeli z powrotem to zmienimy na przykład
na sto i odświeżę, wszystko jest okej i gdybyśmy tutaj sobie zrobili
teraz jeszcze i podejrzeli to zapytanie, to w zakładce timing
możemy zobaczyć ile ono trwało, 21 milisekund. Natomiast czasami może
trwać zdecydowanie dłużej, zależy jak obciążony jest serwer, jak daleko się od nas znajduje. Dlatego
możemy sobie w ten sposób zrobić timeout i teraz prześledźmy na koniec o co tutaj chodzi. Mówiłem
ci, że race nie liczy się tutaj czy będzie resolve czy
reject. Ta promise, która zakończy pierwsza, to będzie
taki hunter wykonany, czyli jeżeli ta będzie miała resolve to wykonujemy
then i nie czekamy na tą, ale jeżeli z kolei ta będzie miała albo ta reject, to
od razu wskakujemy sobie do catch i dlatego ta promise się nam wywołuje
czy robi się resolve. Jak widzieliśmy w zakładce timing po 23 sekundach,
bo tyle musieliśmy czekać na odpowiedź i dopiero wtedy onload się wykonało, a co
za tym idzie resolve. Natomiast wcześniej, po czasie, który ja podałem, czyli 10
milisekundach, wykonała się druga promise, którą podałem tutaj. To jej ustawiłem
settimeout. No i skoro ona zrobiła reject, to już nie czekamy na taką promise, która
była tutaj, więc jest to myślę praktyczny przykład jak można wykorzystać promise race.
Natomiast promise all, tutaj nie potrzebujemy jakiegoś innego praktycznego przykładu. Na
pewno się domyślasz, że zdarzają się sytuacje, gdzie chcemy na raz pobrać kilka różnych danych
z różnych adresów i dopiero kiedy mamy wszystkie, to jakoś się wyświetlić. Na
przykład kiedy pracujemy z API, gdzie pod jednym adresem pobieramy użytkowników, a pod
drugim na przykład listę jakiś zakupów, to będzie to na pewno bardzo
przydatne. No i to by było tyle w tej lekcji, a w kolejnej pokażę ci jeszcze chyba
najciekawszą rzecz, mianowicie jak możemy pracować z generatorami i współpracować
jednocześnie z promise.