Optymalizacja JavaScriptu innej firmy

Skrypty innych firm wpływają na wydajność, dlatego tak ważne jest regularne ich sprawdzanie i stosowanie efektywnych metod ich wczytywania. Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak zoptymalizować wczytywanie zasobów zewnętrznych. Omawiane są w nim te techniki:

  • Wstrzymuję wczytywanie skryptu

  • Leniwe ładowanie niekrytycznych zasobów

  • Wstępne łączenie z wymaganymi źródłami

Dołączona przykładowa aplikacja zawiera prostą stronę internetową z 3 funkcjami pochodzącymi ze źródeł zewnętrznych:

  • Umieszczenie filmu

  • Biblioteka wizualizacji danych do renderowania wykresu liniowego

  • Widżet udostępniania w mediach społecznościowych

.
Zrzut ekranu strony z zaznaczonymi zasobami zewnętrznymi.
Zasoby innych firm w przykładowej aplikacji.
.

Zaczniesz od pomiaru wydajności aplikacji, a następnie zastosujesz każdą z metod, aby poprawić różne aspekty jej działania.

Pomiar wyników

Najpierw otwórz przykładową aplikację w widoku pełnoekranowym:

  1. Aby udostępnić projekt do edycji, kliknij Remiksuj, aby edytować.
  2. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie naciśnij Pełny ekran pełny ekran

Przeprowadź na stronie audyt skuteczności w Lighthouse, aby ustalić ogólną skuteczność:

  1. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.
  2. Kliknij kartę Lighthouse.
  3. Kliknij Urządzenia mobilne.
  4. Zaznacz pole wyboru Skuteczność. Możesz wyczyścić pozostałe pola wyboru w sekcji Kontrole.
  5. Kliknij Symulowany szybki 3G, 4x spowolnienie procesora.
  6. Zaznacz pole wyboru Wyczyść pamięć wewnętrzną.
  7. Kliknij Przeprowadź audyty.

Po przeprowadzeniu kontroli maszyny dokładne wyniki mogą się różnić, ale zauważasz, że pierwsze wyrenderowanie treści (FCP) jest dość wysokie i Lighthouse podpowiada 2 możliwości do zbadania tej sprawy: Wyeliminuj zasoby blokujące renderowanie i Wstępnie połącz z wymaganymi źródłami. (Nawet jeśli wszystkie wskaźniki są zaznaczone na zielono, optymalizacje nadal przyniosą poprawę).

Zrzut ekranu pokazujący 2,4-sekundowe FCP i 2 możliwości: wyeliminowanie zasobów blokujących renderowanie i wstępne łączenie z wymaganymi źródłami.

Odrocz kod JavaScript innej firmy

Kontrola Eliminacja zasobów blokujących renderowanie wykazała, że możesz zaoszczędzić czas, opóźniając działanie skryptu pochodzącego z d3js.org:

Zrzut ekranu pokazujący wyeliminowanie kontroli zasobów blokujących renderowanie z zaznaczonym skryptem d3.v3.min.js.

D3.js to biblioteka JavaScriptu do tworzenia wizualizacji danych. Plik script.js w przykładowej aplikacji używa funkcji narzędzia D3 do utworzenia wykresu liniowego SVG i dołączenia go do strony. Kolejność działań ma znaczenie: script.js musi zostać uruchomiony po przeanalizowaniu dokumentu i załadowaniu biblioteki D3, dlatego znajduje się w elemencie index.html tuż przed zamykającym tagiem </body>.

Skrypt D3 jest jednak zawarty w elemencie <head> strony, który blokuje analizę pozostałego dokumentu:

Zrzut ekranu strony index.html z zaznaczonym tagiem skryptu w nagłówku.

Dwa magiczne atrybuty mogą odblokować parser, gdy dodasz go do tagu skryptu:

  • async dba o to, aby skrypty były pobierane w tle i uruchamiane przy pierwszej okazji po zakończeniu pobierania.

  • defer zapewnia, że skrypty są pobierane w tle i uruchamiane po zakończeniu analizy.

Ten wykres nie ma krytycznego znaczenia dla ogólnej strony i najprawdopodobniej znajduje się w części strony widocznej po przewinięciu, dlatego użyj parametru defer, by mieć pewność, że nie ma blokowania parsera.

Krok 1. Wczytaj skrypt asynchronicznie za pomocą atrybutu defer

W wierszu 17 w pliku index.html dodaj atrybut defer do elementu <script>:

<script src="https://d3js.org/d3.v3.min.js" defer></script>

Krok 2. Zadbaj o właściwą kolejność działań

Teraz, gdy D3 jest odroczony, zadanie script.js zostanie uruchomione, zanim będzie gotowy D3, co spowoduje błąd.

Skrypty z atrybutem defer są wykonywane w kolejności, w jakiej zostały określone. Aby mieć pewność, że usługa script.js zostanie wykonana po utworzeniu elementu D3, dodaj do niego element defer i przenieś go w górę do <head> dokumentu, zaraz za elementem <script> D3. Teraz nie blokuje on już parsera, a pobieranie rozpoczyna się wcześniej.

<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>

Leniwe ładowanie zasobów innych firm

leniwe ładowanie można stosować we wszystkich zasobach w części strony widocznej po przewinięciu.

Przykładowa aplikacja ma film z YouTube umieszczony w elemencie iframe. Aby sprawdzić, ile żądań wysyła strona i które z nich pochodzą z umieszczonego elementu iframe YouTube:

  1. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie naciśnij Pełny ekran pełny ekran
  2. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.
  3. Kliknij kartę Sieć.
  4. Zaznacz pole wyboru Wyłącz pamięć podręczną.
  5. W menu Throttling wybierz Szybka sieć 3G.
  6. Odśwież stronę.

Zrzut ekranu przedstawiający panel Sieć w Narzędziach deweloperskich.

Z informacji w panelu Sieć wynika, że strona wysłała łącznie 28 żądań i przeniosła prawie 1 MB skompresowanych zasobów.

Aby zidentyfikować żądania, które przesłał iframe YouTube, odszukaj identyfikator filmu 6lfaiXM6waw w kolumnie Inicjator. Aby zgrupować wszystkie żądania według domeny:

  • W panelu Sieć kliknij prawym przyciskiem myszy tytuł kolumny.

  • W menu wybierz kolumnę Domeny.

  • Aby posortować żądania według domeny, kliknij tytuł kolumny Domeny.

Z nowego sortowania wynika, że istnieją dodatkowe żądania do domen Google. Łącznie element iframe YouTube wysyła 14 żądań skryptów, arkuszy stylów, obrazów i czcionek. Jeśli jednak użytkownik nie przewinie strony w dół, aby odtworzyć film, nie są one tak naprawdę potrzebne.

Oczekiwanie na leniwe ładowanie filmu, dopóki użytkownik nie przewinie w dół do danej sekcji strony, zmniejsza liczbę żądań, które strona początkowo wysyła. Dzięki temu użytkownicy zaoszczędzą i przyspiesza początkowe wczytywanie.

Jednym ze sposobów wdrożenia leniwego ładowania jest użycie Intersection Observer – interfejsu API przeglądarki, który powiadamia Cię, gdy element otworzy się w oknie przeglądarki lub go opuści.

Krok 1. Zablokuj możliwość wstępnego wczytywania filmu

Aby leniwie ładować element iframe wideo, musisz najpierw uniemożliwić jego ładowanie w zwykły sposób. Aby to zrobić, zastąp atrybut src atrybutem data-src, aby określić adres URL filmu:

<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

data-src to atrybut danych, który umożliwia przechowywanie dodatkowych informacji w standardowych elementach HTML. Atrybut danych może mieć dowolną nazwę, ale musi zaczynać się od „data-”.

Element iframe bez parametru src po prostu się nie załaduje.

Krok 2. Użyj obserwacji intersekcji, by leniwie ładować film

Aby film był ładowany, gdy użytkownik przewija stronę, musisz wiedzieć, kiedy to się dzieje. Na tym właśnie polega interfejs Intersection Observer API. Interfejs Intersection Observer API pozwala zarejestrować funkcję wywołania zwrotnego, która jest wykonywana, gdy element, który chcesz śledzić, pojawia się lub opuszcza widoczny obszar.

Na początek utwórz nowy plik i nadaj mu nazwę lazy-load.js:

  • Kliknij Nowy plik i nadaj mu nazwę.
  • Kliknij Dodaj ten plik.

Dodaj tag skryptu do nagłówka dokumentu:

 <script src="/lazy-load.js" defer></script>

W narzędziu lazy-load.js utwórz nowy obiekt IntersectionObserver i przekaż go funkcję wywołania zwrotnego, aby uruchomić ją:

// create a new Intersection Observer
let observer = new IntersectionObserver(callback);

Teraz określ dla observer element docelowy do obejrzenia (w tym przypadku element iframe filmu), przekazując go jako argument w metodzie observe:

// the element that you want to watch
const element = document.querySelector('iframe');

// register the element with the observe method
observer.observe(element);

callback otrzymuje listę obiektów IntersectionObserverEntry i samego obiektu IntersectionObserver. Każdy wpis zawiera element target i właściwości opisujące jego wymiary, położenie, czas pojawienia się w widocznym obszarze i inne informacje. Jedna z właściwości obiektu IntersectionObserverEntry to isIntersecting – wartość logiczna równa się true, gdy element wchodzi w widoczny obszar.

W tym przykładzie target to iframe. isIntersecting równa się true, gdy target wchodzi w widoczny obszar. Aby zobaczyć, jak to działa, zastąp callback tą funkcją:

let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(entry => {
      console.log(entry.target);
      console.log(entry.isIntersecting);
    });
  });
  1. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie naciśnij Pełny ekran pełny ekran
  2. Naciśnij „Control + Shift + J” (lub „Command + Option + J” na Macu), aby otworzyć Narzędzia deweloperskie.
  3. Kliknij kartę Konsola.

Spróbuj przewinąć stronę w górę i w dół. Powinna pojawić się wartość zmiany isIntersecting oraz element docelowy zarejestrowany w konsoli.

Aby wczytać film, gdy użytkownik przewinie stronę do jego pozycji, użyj parametru isIntersecting, aby uruchomić funkcję loadElement, która pobiera wartość z wartości data-src elementu iframe i ustawia ją jako atrybut src elementu iframe. Powoduje to wczytanie filmu. Następnie po załadowaniu filmu wywołaj metodę unobserve na observer, by zatrzymać oglądanie elementu docelowego:

let observer = new IntersectionObserver(function (entries, observer) {
  entries.forEach(entry => {
    console.log(entry.target);
    console.log(entry.isIntersecting);
  });
});
    if (entry.isIntersecting) {
      // do this when the element enters the viewport
      loadElement(entry.target);
      // stop watching
      observer.unobserve(entry.target);
    }
  });
});

function loadElement(element) {
  const src = element.getAttribute('data-src');
  element.src = src;
}

Krok 3. Ponownie oceń skuteczność

Aby zobaczyć, jak zmienił się rozmiar i liczba zasobów, otwórz panel Sieć w Narzędziach deweloperskich i ponownie załaduj stronę. Z panelu Sieć wynika, że strona wysłała 14 żądań i zajęła tylko 260 KB. To znacząca poprawa!

Przewiń stronę w dół i zwróć uwagę na panel Network. Gdy przejdziesz do filmu, strona powinna wywołać dodatkowe żądania.

Wstępnie połącz z wymaganymi źródłami

Udało Ci się odłożyć niekrytyczny JavaScript i leniwie ładować żądania do YouTube, więc nadszedł czas na optymalizację pozostałych treści zewnętrznych.

Dodanie atrybutu rel=preconnect do linku informuje przeglądarkę, że ma nawiązać połączenie z domeną przed wysłaniem żądania dotyczącego danego zasobu. Tego atrybutu najlepiej używać w przypadku źródeł dostarczających zasoby, których strona na pewno potrzebuje.

Audyt Lighthouse przeprowadziliśmy w pierwszym kroku sugerowanego w sekcji Wstępne łączenie z wymaganymi źródłami. Możesz zaoszczędzić około 400 ms, nawiązując wczesne połączenia ze stronami staticxx.facebook.com i youtube.com:

Nawiąż połączenie z wymaganą kontrolą źródeł z wyróżnioną domeną staticxx.facebook.com.

Ponieważ film w YouTube jest teraz ładowany leniwie, źródłem widżetu udostępniania w mediach społecznościowych pozostaje tylko staticxx.facebook.com. Nawiązanie wcześniejszego połączenia z tą domeną wymaga dodania tagu <link> do sekcji <head> dokumentu:

  <link rel="preconnect" href="https://staticxx.facebook.com">

Ponownie oceń skuteczność

Oto stan strony po optymalizacji. Wykonaj czynności opisane w sekcji Pomiar wydajności ćwiczenia z programowania, aby przeprowadzić kolejny audyt Lighthouse.

Audyt Lighthouse pokazujący 1 sekundę FCP i wynik wydajności na poziomie 99.