JavaScript z podziałem kodu

Wczytywanie dużych zasobów JavaScriptu znacząco wpływa na szybkość działania strony. Podział JavaScript na mniejsze fragmenty i pobierasz tylko to, co jest niezbędne aby strona działała podczas uruchamiania, może znacznie poprawić obciążenie strony responsywność strony, która z kolei może polepszyć interakcje z następną interakcją. Barwiony (INP).

Podczas pobierania, analizowania i kompilowania dużych plików JavaScript może dojść nie odpowiada przez dłuższy czas. Elementy strony są widoczne, ponieważ są są częścią początkowego kodu HTML strony i mają styl właściwy CSS. Ponieważ jednak kod JavaScript tych elementów interaktywnych – a także innych skryptów wczytywanych przez stronę – może to być np. analizowanie i wykonywanie kodu JavaScript w celu jej poprawnego funkcjonowania. może mieć wrażenie, że interakcja z nimi jest znacznie większa, z opóźnieniem, a nawet całkowicie uszkodzonych.

Dzieje się tak często, gdy wątek główny jest blokowany podczas analizowania JavaScriptu i zebrane w głównym wątku. Jeśli ten proces trwa zbyt długo, jest bardziej interaktywny elementy strony mogą nie reagować wystarczająco szybko na dane wejściowe użytkownika. Jedno rozwiązanie tego problemu to wczytywanie tylko tego kodu JavaScript, który jest niezbędny do działania strony, a odroczenie innych skryptów JavaScript do późniejszego załadowania za pomocą metody znanej jako kod dzielone na dwie części. W tej części skupimy się na drugiej z tych 2 technik.

Ogranicz analizowanie i wykonywanie JavaScriptu podczas uruchamiania dzięki podziałowi kodu

Lighthouse wyświetla ostrzeżenie, gdy wykonanie JavaScriptu trwa dłużej niż 2 razy i kończy się niepowodzeniem, jeśli trwa dłużej niż 3,5 sekundy. Nadmiarowy kod JavaScript analizowanie i wykonywanie tagów może być problemem w dowolnym miejscu strony, cyklu życia, ponieważ może to zwiększyć opóźnienia interakcji jeśli czas interakcji użytkownika ze stroną zbiega się z momentem główne zadania w wątku odpowiedzialnym za przetwarzanie i wykonywanie JavaScriptu są w domu.

Co więcej, nadmierne wykonywanie i analiza kodu JavaScript jest szczególnie problematyczny przy wstępnym wczytaniu strony, ponieważ to właśnie ten punkt cykl życia strony, który z dużym prawdopodobieństwem będzie korzystał z niej. Całkowity czas blokowania (TBT) – wskaźnik responsywności ładowania – jest silnie skorelowany. z wartością INP, co sugeruje, że użytkownicy mają tendencję do podejmowania prób interakcji podczas wstępnego wczytywania strony.

Audyt Lighthouse, który podaje czas poświęcony na wykonanie każdego pliku JavaScript żądania stron są przydatne, bo pomagają zidentyfikować skrypty mogą być wskazane do podziału kodu. Następnie możesz przejść dalej o korzystając z narzędzia do obudowy w Narzędziach deweloperskich w Chrome, aby zidentyfikować dokładnie te części JavaScript strony jest nieużywany podczas wczytywania strony.

Dzielenie kodu to przydatna technika, która pozwala zmniejszyć ilość początkowego JavaScriptu na stronie ładunki. Pozwala podzielić pakiet JavaScript na 2 części:

  • JavaScript wymagany przy wczytywaniu strony, więc nie może zostać wczytany w żadnym innym miejscu obecnie się znajdujesz.
  • Pozostały kod JavaScript, który można wczytać później, najczęściej w punkcie, w którym użytkownik wchodzi w interakcję z danym elementem interaktywnym stronę.

Kod można podzielić za pomocą składni dynamicznej import(). Ten składni – w przeciwieństwie do elementów <script>, które wysyłają żądania dotyczące danego zasobu JavaScript. podczas uruchamiania – wysyła żądanie o zasób JavaScript w późniejszym czasie podczas cykl życia strony.

document.querySelectorAll('#myForm input').addEventListener('blur', async () => {
  // Get the form validation named export from the module through destructuring:
  const { validateForm } = await import('/validate-form.mjs');

  // Validate the form:
  validateForm();
}, { once: true });

W poprzednim fragmencie kodu JavaScript moduł validate-form.mjs jest pobrane, przeanalizowane i wykonane tylko wtedy, gdy użytkownik zamazuje dowolny <input> pól. W takiej sytuacji zasób JavaScript odpowiedzialny za stosowanie logiki weryfikacji formularza jest uwzględniane na stronie tylko wtedy, gdy są wykorzystywane najczęściej.

Pakiety JavaScript, takie jak webpack, Parcel, Rollup i esbuild, mogą być skonfigurowane w taki sposób, aby dzielić pakiety JavaScript na mniejsze fragmenty, gdy natrafisz w kodzie źródłowym na dynamiczne wywołanie import(). Większość z tych narzędzi jest to automatycznie, ale w szczególności tworzenie kodu wymaga włączenia tej opcji optymalizacji.

Przydatne uwagi na temat dzielenia kodu

Dzielenie kodu jest skutecznym sposobem ograniczania rywalizacji o główne wątki już podczas jego początkowego wczytywania, warto pamiętać o kilku kwestiach. aby sprawdzić kod źródłowy JavaScript pod kątem możliwości podziału kodu.

Jeśli to możliwe, używaj kreatora pakietów

Zazwyczaj deweloperzy używają modułów JavaScript podczas jego rozwoju. To doskonałe rozwiązanie dla programistów, poprawia czytelność i łatwość obsługi kodu. Istnieją jednak pewne nieoptymalne cechy wydajności, które mogą wystąpić przy wysyłaniu kodu JavaScript. modułów do produkcji.

Przede wszystkim do przetwarzania i optymalizowania źródła należy korzystać z usług dostawcy pakietów włącznie z modułami, które mają zostać podzielone. Pakiety są bardzo skuteczne nie tylko optymalizowanie kodu źródłowego JavaScriptu, ale także pozwala na równoważenie czynników związanych z wydajnością, takich jak rozmiar pakietów ze współczynnikiem kompresji. Skuteczność kompresji zwiększa się wraz z rozmiarem pakietu, ale także starają się, by pakiety nie były tak duże, długie zadania ze względu na ocenę skryptu.

Pozwalają też na uniknięcie problemów z dostarczeniem dużej liczby rozłączonych modułów. w sieci. Architektura wykorzystująca moduły JavaScriptu ma zwykle duże, złożone drzewa modułów. Po rozgrupowaniu drzew modułów każdy moduł reprezentuje osobne żądanie HTTP, dlatego interaktywność aplikacji internetowej może być opóźniona, jeśli Nie łącz modułów w pakiety. Mimo że za pomocą atrybutu Wskazówka dotycząca zasobu <link rel="modulepreload"> umożliwiająca szybkie wczytywanie dużych drzew modułów ale pakiety JavaScript są nadal lepsze od ładowania z całego świata.

Nie wolno przez przypadek wyłączać kompilacji strumieniowania

Mechanizm JavaScript V8 w Chromium zapewnia wiele gotowych optymalizacji aby zapewnić jak najszybsze wczytywanie produkcyjnego kodu JavaScript. Jedna z takich optymalizacji nosi nazwę kompilacji strumieniowej, która – jak przyrostowa analiza składniowa kodu HTML przesyłanego do przeglądarki – kompiluje przesyłane strumieniowo fragmenty JavaScript pobieranych z sieci.

Aby upewnić się, że kompilacja strumieniowa będzie wykonywana w przypadku Twojego kanału, aplikacja internetowa w Chromium:

  • Przekształć kod produkcyjny, aby uniknąć używania modułów JavaScript. Pakiety może przekształcić kod źródłowy JavaScript na podstawie celu kompilacji oraz cele są często powiązane z danym środowiskiem. V8 będzie stosować strumieniowanie do dowolnego kodu JavaScript, który nie korzysta z modułów, oraz skonfigurować pakiet usług tak, aby przekształcał kod modułu JavaScript w składnię który nie korzysta z modułów JavaScript ani ich funkcji.
  • Jeśli chcesz przesłać moduły JavaScriptu do środowiska produkcyjnego, użyj metody .mjs . Niezależnie od tego, czy produkcyjny JavaScript używa modułów, brak specjalnego typu treści dla JavaScriptu, który korzysta z modułów w porównaniu z JavaScriptem. w przeciwnym razie. W przypadku V8 rezygnujesz ze strumieniowania danych podczas wysyłania modułów JavaScriptu w środowisku produkcyjnym za pomocą interfejsu .js . Jeśli używasz rozszerzenia .mjs dla modułów JavaScript, V8 może upewnij się, że kompilacja strumieniowa opartego na modułowym kodzie JavaScript nie działa.

Niech te kwestie zniechęcają Cię do dzielenia kodu. Koduj to skuteczny sposób ograniczania wstępnych ładunków JavaScriptu użytkowników, ale korzystając z narzędzia do tworzenia pakietów i dowiedzieć się, jak zachować kompilację, można zadbać o to, aby produkcyjny kod JavaScript dla użytkowników z myślą o użytkownikach.

Demonstracja importu dynamicznego

Webpack

webpack jest dostarczany z wtyczką o nazwie SplitChunksPlugin, która umożliwia skonfigurować sposób dzielenia plików JavaScript przez narzędzie pakietu. Webpack rozpoznaje zarówno dynamiczne import() i statyczne instrukcje import. Działanie funkcji SplitChunksPlugin można zmodyfikować, określając opcję chunks w Konfiguracja:

  • chunks: async to wartość domyślna i odnosi się do dynamicznych wywołań import().
  • Parametr chunks: initial odnosi się do statycznych wywołań typu import.
  • Reguła chunks: all obejmuje zarówno import dynamiczny import(), jak i statyczny, dzięki czemu aby udostępnić fragmenty między importami async i initial.

Domyślnie, gdy pakiet internetowy napotyka dynamiczną instrukcję import(). jego utworzy osobny fragment dla tego modułu:

/* main.js */

// An application-specific chunk required during the initial page load:
import myFunction from './my-function.js';

myFunction('Hello world!');

// If a specific condition is met, a separate chunk is downloaded on demand,
// rather than being bundled with the initial chunk:
if (condition) {
  // Assumes top-level await is available. More info:
  // https://v8.dev/features/top-level-await
  await import('/form-validation.js');
}

W przypadku domyślnej konfiguracji pakietu internetowego dla poprzedniego fragmentu kodu powstaje 2 razy: (w osobnych częściach):

  • Fragment main.js – który jest klasyfikowany jako fragment initial – który zawiera moduły main.js i ./my-function.js.
  • Fragment async, który zawiera tylko form-validation.js (zawierający hasz pliku w nazwie zasobu, jeśli został skonfigurowany). Ten fragment jest tylko pobrany czy i kiedy condition jest prawdą.

Ta konfiguracja pozwala odroczyć wczytywanie fragmentu form-validation.js do jest naprawdę potrzebna. Może to poprawić szybkość ładowania dzięki ograniczeniu liczby skryptów oceny podczas początkowego wczytywania strony. Pobieranie i ocena skryptu dla fragmentu form-validation.js występuje, gdy zostanie spełniony określony warunek, w polu W takim przypadku pobrany zostanie moduł importowany dynamicznie. Przykładem może być warunku, w którym element polyfill jest pobierany tylko dla określonej przeglądarki, z wcześniejszego przykładu – zaimportowany moduł jest niezbędny do interakcji użytkownika.

Z drugiej strony zmień konfigurację SplitChunksPlugin, aby określić chunks: initial zapewnia, że kod jest dzielony tylko na początkowych fragmentach. Są to fragmentów, np. zaimportowanych statycznie lub wymienionych w elemencie entry pakietu internetowego usługi. W poprzednim przykładzie wynikowy fragment byłby kombinacji form-validation.js i main.js w jednym pliku skryptu, co może pogorszyć szybkość wczytywania strony na początku.

Opcje SplitChunksPlugin można również skonfigurować tak, aby oddzielić większe na kilka mniejszych, np. za pomocą opcji maxSize instruowania pakietu internetowego, aby podzielić fragmenty na osobne pliki, jeśli przekroczą one limit określona przez maxSize. Dzielenie dużych plików skryptów na mniejsze poprawić czas reagowania na obciążenie, ponieważ w niektórych przypadkach ocena skryptów obciążająca procesor zadania są dzielone na mniejsze zadania, które rzadziej blokują główne zadania. przez dłuższy czas.

Poza tym generowanie większych plików JavaScript oznacza również, że skrypty jest narażone na unieważnienie pamięci podręcznej. Na przykład jeśli wysyłasz bardzo duży skrypt z kodem platformy i własnej aplikacji, pakiet może zostać unieważniony, jeśli tylko platforma zostanie zaktualizowana, ale nic więcej w pakiecie.

Z drugiej strony mniejsze pliki skryptów zwiększają prawdopodobieństwo zwrotu użytkownik pobiera zasoby z pamięci podręcznej, dzięki czemu strony wczytują się szybciej do kolejnych wizyt. Jednak mniejsze pliki lepiej radzą sobie z kompresją niż większe. i może wydłużyć czas przesyłania danych w obie strony podczas wczytywania strony bez pamięci podręcznej przeglądarki. Zachowaj ostrożność, aby zachować równowagę między buforowaniem takich jak wydajność, wydajność kompresji i czas oceny skryptu.

wersja demonstracyjna pakietu webpack

demonstracja pakietu internetowego SplitChunksPlugin.

Sprawdź swoją wiedzę

Który typ instrukcji import jest używany podczas wykonywania kodu podział?

Dynamiczny import().
Dobrze!
Statyczny import.
Spróbuj ponownie.

Który typ instrukcji import musi znajdować się na górze modułu JavaScript i nie znajduje się w żadnym innym miejscu.

Dynamiczny import().
Spróbuj ponownie.
Statyczny import.
Dobrze!

Jaka jest właściwość SplitChunksPlugin w pakiecie internetowym? różnica między fragmentem async a fragmentem initial fragment?

async fragmentu zostało wczytane za pomocą dynamicznej metody import() i fragmenty (initial) zostały wczytane przy użyciu elementów statycznych import
Dobrze!
async fragmentu zostało wczytane przy użyciu statycznego parametru import i fragmenty (initial) są wczytywane za pomocą kreacji dynamicznych import()
Spróbuj ponownie.

Następny krok: leniwe ładowanie obrazów i elementów <iframe>

Choć jest to dość drogi rodzaj zasobu, JavaScript nie jest tylko taki typ zasobu, którego wczytywanie można odroczyć. Obraz i elementy <iframe> same w sobie mogą być kosztownymi zasobami. Podobnie jak w przypadku JavaScriptu, może opóźnić wczytywanie obrazów i elementu <iframe> dzięki leniwemu ładowaniu . Omówimy to w następnym module tego kursu.