Kod

Zarządzanie pętlą zdarzeń w JavaScript - 1

Zarządzanie pętlą zdarzeń w JavaScript - 1 / Skillbox Media

Zdobądź mistrzostwo w zawodzie front-end developera ze szczególnym uwzględnieniem sztucznej inteligencji

Dowiedz się więcej

Zrozumienie mechanizmów pętli zdarzeń to ważny krok na drodze do rozwoju zawodowego dla średniego szczebla developera.

O pętlach zdarzeń opowie teraz Alexander Kuzmin, doświadczony programista z ponad dziesięcioletnim stażem w branży front-end i szef działu rozwoju rozwiązań klienckich w IT-Park. Oddajmy głos naszemu ekspertowi.

Zrozumienie procesów asynchronicznych w JavaScript

Każdy język programowania oferuje unikalne metody implementacji obliczeń równoległych. Na przykład w językach takich jak C++ problem ten rozwiązuje się poprzez utworzenie osobnego wątku lub nawet procesu, który może być wykonywany w innym systemie obliczeniowym.

Aleksander Kuzmin

Główny programista i dyrektor działu rozwoju klienta w IT-Park

Kiedy zachodzi potrzeba przeniesienia zadania do wątku, na przykład Przykład: „Wykonaj obliczenia i zapisz wynik w bazie danych”. Kiedy mówimy „baza danych, a wrócę po nią później”, mamy do czynienia z procesami asynchronicznymi.

Oznacza to, że kod, który zainicjował wykonywanie, nie przestaje czekać na jego zakończenie, ale kontynuuje swoją pracę. Jeśli jednak musimy poczekać na wynik, wiele współczesnych języków programowania oferuje konstrukcje async i wait, które pozwalają nam synchronizować wykonywanie kodu.

Asynchroniczność to kluczowa cecha JavaScriptu. W erze poprzedzającej Node.JS był to zasadniczo jedyny język używany do tworzenia skryptów po stronie klienta w internecie (chociaż Internet Explorer obsługiwał VB Script, jego użycie było niezwykle rzadkie). Dziś trudno wyobrazić sobie sieć, w której każde żądanie do serwera wymagałoby przeładowania strony. Zamiast tego obserwujemy wzrost liczby aplikacji jednostronicowych, w których rozpoznawanie adresów URL i renderowanie treści odbywa się po stronie klienta.

Żądania do serwera są wysyłane asynchronicznie: żądanie jest inicjowane (za pośrednictwem XMLHttpRequest lub XHR), a program kontynuuje wykonywanie bez oczekiwania na odpowiedź. Gdy serwer dostarczy dane, obiekt XHR otrzymuje sygnał i wywołuje funkcję zwrotną określoną przed wysłaniem żądania.

Gdy JavaScript musi czekać na żądanie, przestaje przetwarzać zdarzenia, co może spowodować zawieszenie się strony. Aby zapewnić płynne działanie, żądania są wykonywane poza głównym kontekstem wykonania. Operacje wymagające oczekiwania na wynik przed kontynuowaniem wykonywania kodu nazywane są blokowaniem. Szczegóły dotyczące tych operacji zostaną omówione w drugiej części artykułu.

Istota tkwi w strukturze języka.

Przy prawidłowym użyciu narzędzi językowych, sekwencyjne wykonywanie kodu w jednym wątku nie zakłóca przetwarzania zdarzeń i reakcji na nie. Użytkownik może komfortowo korzystać z interfejsu bez opóźnień, awarii czy zawieszania się.

Pętla zdarzeń w JavaScript: zarządzanie procesami asynchronicznymi

Aby ten złożony proces działał wydajnie, JavaScript opracował mechanizm zarządzający kolejnością wykonywania kodu. Ponieważ język jest jednowątkowy, zaistniała potrzeba integracji z bieżącym kontekstem wykonania. Mechanizm ten nazywa się pętlą zdarzeń.

Słowo „pętla” W języku angielskim słowo „loop” tłumaczy się jako „loop”, co doskonale ilustruje jego znaczenie: jest to kolejka o zamkniętej pętli.

Pętla zdarzeń zarządza kolejnością kontekstów wykonywania poprzez tworzenie stosu. Jest on tworzony w momencie wystąpienia zdarzenia lub wywołania funkcji. Odpowiedź na zdarzenie jest dodawana do kolejki wykonywania w pętli zdarzeń, która sekwencyjnie przetwarza kod w każdym nowym cyklu. W tym procesie funkcja powiązana ze zdarzeniem jest wywoływana natychmiast po zakończeniu bieżącego kontekstu wykonywania.

W JavaScript istnieje interakcja między kolejkami wykonywania synchronicznego i asynchronicznego, które ściśle ze sobą współpracują. Kolejka synchroniczna, reprezentowana przez stos, tworzy sekwencję wywołań i przekazuje je do kolejki asynchronicznej, zwanej pętlą zdarzeń. Ta ostatnia kolejka odpowiada za wykonywanie funkcji zaplanowanych do wykonania po zakończeniu bieżącego kontekstu wykonywania.

Aby zapewnić spójność danych, każda funkcja musi zostać wykonana w całości. Wynika to z jednowątkowej natury JavaScript, a także z szeregu innych cech, w tym zamknięć, typowych dla języków programowania funkcyjnego. W tym kontekście pojedynczy wątek jest implementowany w formacie kolejki kontekstu wykonania, w której następuje interpolacja funkcji przetwarzanych w pętli zdarzeń.

Diagram pętli zdarzeń. Na każdym etapie sprawdzana jest jedna z jej kolejek. Pomimo nazw, setImmediate jest wykonywana wewnątrz pętli w każdej iteracji (tick), a nextTick jest wywoływana w momencie wykonania – pomiędzy etapami pętli.

W JavaScript istnieje coś takiego jak „kontekst funkcji”. Istnieje jednak alternatywny termin – „kontekst wykonania”. Kontekst ten to ciało funkcji, które zawiera wszystkie zmienne i funkcje zagnieżdżone, i po angielsku nazywa się go „zakresem”. Bardzo ważne jest rozróżnienie tych terminów, ponieważ oznaczają one zupełnie różne koncepcje.

Proces tworzenia kontekstu wykonania

JavaScript jest językiem interpretowanym, co oznacza, że ​​kod jest przetwarzany przez interpreter, który wykonuje go wiersz po wierszu. Proces ten ma jednak swoją specyfikę.

Gdy skrypt rozpoczyna wykonywanie w interpreterze, tworzony jest kontekst globalny i zakres globalny. W ramach tego procesu tworzony jest obiekt zmiennej, znany jako obiekt zmiennej (Variable Object, VO).

Jest on tworzony ze zmiennych reprezentujących deklaracje funkcji oraz atrybuty tych funkcji, zgodnie z określoną zasadą. Interpreter analizuje kod i wykrywa wszystkie istotne deklaracje:

  • zmienne zdefiniowane za pomocą słowa kluczowego var (lub const i let w ES6 i nowszych wersjach);
  • funkcje utworzone za pomocą słowa kluczowego function bez określania przypisania.

To tworzy obiekt zmiennej (VO) w bieżącym kontekście wykonania. Następnie VO jest wyodrębniany z zakresu zewnętrznego, a wcześniej utworzony VO jest do niego dodawany. Na koniec jest on wypełniany parametrami funkcji i ich wartościami w czasie wykonywania.

Należy pamiętać, że miejsce zdefiniowania funkcji nie ma znaczenia. Zmienne, podobnie jak funkcje, można deklarować w dowolnym miejscu programu.

Rozważmy poniższy skrypt:

Narracja dla tego skryptu jest tworzona w następujący sposób:

Po tym skrypt rozpocznie wykonywanie zgodnie z następującym planem:

Zmodyfikujmy skrypt, wstawiając wywołanie funkcji za pomocą setTimeout z opóźnieniem ustawionym na zero.

Na pierwszy rzut oka mogłoby się wydawać, że funkcja func wykona się natychmiast i bez żadnych opóźnień. Jednak jest to dalekie od prawdy. W rzeczywistości wystąpią następujące zdarzenia:

Związek między programowaniem front-end a sztuczną inteligencją

Dzięki pracy programistów front-end możemy polubić i zostawić komentarze, dodać produkty do koszyka i łatwo poruszać się po mapach online. Na tym kursie nauczysz się tworzyć interfejsy dla usług sieciowych, wykorzystując języki programowania i różne technologie. Będziesz potrafił tworzyć aplikacje, takie jak harmonogramy zadań, komunikatory internetowe i sklepy internetowe.

Dowiedz się więcej