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. Z tego Codelab dowiesz się, jak zoptymalizować wczytywanie zasobów innych firm. Obejmuje ona te techniki:

  • Opóźnianie wczytywania skryptu

  • Leniwe ładowanie niekrytycznych zasobów

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

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

  • Wstawiony film

  • Biblioteka wizualizacji danych do renderowania wykresu liniowego

  • Widget udostępniania w mediach społecznościowych

Zrzut ekranu strony z wyróżnionymi zasobami innych firm
Zasoby innych firm w przykładowej aplikacji.

Najpierw zmierz skuteczność aplikacji, a potem zastosuj każdą technikę, aby poprawić różne aspekty jej skuteczności.

Pomiar wyników

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

  1. Kliknij Remix to Edit (Zmiksuj do edycji), aby umożliwić edycję projektu.
  2. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekranpełny ekran.

Aby ustalić wydajność bazową, przeprowadź audyt wydajnościLighthouse na stronie:

  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 Wydajność. (możesz odznaczyć pozostałe pola w sekcji Audyt).
  5. Kliknij Symulowana szybka sieć 3G, 4-krotne spowolnienie CPU.
  6. Zaznacz pole wyboru Wyczyść pamięć podręczną.
  7. Kliknij Przeprowadź audyty.

Gdy przeprowadzisz audyt na swoim urządzeniu, dokładne wyniki mogą się różnić, ale powinieneś zauważyć, że czas pierwszego wyrenderowania treści (FCP) jest dość długi, a Lighthouse sugeruje 2 możliwości rozwiązania tego problemu: usunięcie zasobów blokujących renderowanieuprzednie połączenie z wymaganymi źródłami. (nawet jeśli wszystkie dane są zielone, optymalizacje nadal przynoszą 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

Podczas kontroli Eliminowanie zasobów blokujących renderowanie stwierdziliśmy, że możesz zaoszczędzić trochę czasu, opóźniając skrypt pochodzący z d3js.org:

Zrzut ekranu z audytem wyeliminowania zasobów blokujących renderowanie z wyróżnionym skryptem d3.v3.min.js

D3.js to biblioteka JavaScript do tworzenia wizualizacji danych. Plik script.js w przykładowej aplikacji używa funkcji narzędziowych D3 do utworzenia wykresu liniowego SVG i dołączenia go do strony. Ważna jest kolejność operacji: funkcja script.js musi zostać wykonana po przeanalizowaniu dokumentu i wczytaniu biblioteki D3, dlatego jest uwzględniona tuż przed zamykającym tagiem </body> w funkcji index.html.

Skrypt D3 jest jednak uwzględniony w sekcji <head> strony, co blokuje analizę reszty dokumentu:

Zrzut ekranu pliku index.html z wyróżnionym tagiem skryptu w sekcji nagłówka.

Dodanie do tagu skryptu 2 magicznych atrybutów może odblokować parsowanie:

  • async zapewnia, że skrypty są pobierane w tle i wykonywane przy pierwszej okazji po zakończeniu pobierania.

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

Ten wykres nie jest tak naprawdę kluczowy dla całej strony i najprawdopodobniej będzie widoczny poniżej załamu, więc użyj defer, aby sprawdzić, czy nie ma blokowania przez parsowanie.

Krok 1. Załaduj skrypt asynchronicznie za pomocą atrybutu defer

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

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

Krok 2. Upewnij się, że operacje są wykonywane w prawidłowej kolejności

Ponieważ D3 jest opóźnione, funkcja script.js zostanie wykonana, zanim D3 będzie gotowe, co spowoduje błąd.

Skrypty z atrybutem defer są wykonywane w kolejności, w jakiej zostały określone. Aby mieć pewność, że element script.js zostanie wykonany po zakończeniu etapu D3, dodaj do niego element defer i przesuń go do <head> dokumentu, tuż za elementem <script> etapu D3. Teraz nie blokuje już parsowania i 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 z innych witryn

Wszystkie zasoby, które znajdują się poniżej pola widzenia, nadają się do leniwego ładowania.

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 osadzonego elementu iframe YouTube:

  1. Aby wyświetlić podgląd strony, kliknij Wyświetl aplikację. Następnie kliknij Pełny ekranpełny ekran.
  2. Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
  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 panelu Sieć wynika, że strona wysłała łącznie 28 żądań i przesłała prawie 1 MB zasobów skompresowanych.

Aby zidentyfikować żądania wysłane przez YouTube iframe, poszukaj identyfikatora filmu 6lfaiXM6waw w kolumnie Initiator (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.

Nowe sortowanie ujawnia, że do domen Google wysyłane są dodatkowe żądania. W ogóle element iframe YouTube wysyła 14 żądań skryptów, arkuszy stylów, obrazów i czcionek. Jeśli jednak użytkownicy nie przewiną strony w dół, aby odtworzyć film, nie będą potrzebować wszystkich tych zasobów.

Odczekanie z leniwym wczytaniem filmu do momentu, gdy użytkownik przewinie stronę w dół, zmniejsza liczbę żądań wysyłanych przez stronę na początku. Dzięki temu podejściu oszczędzasz dane użytkowników i przyspieszasz wczytywanie.

Jednym ze sposobów implementacji wolnego wczytywania jest użycie Intersection Observer, czyli interfejsu API przeglądarki, który powiadamia, gdy element wchodzi do widocznego obszaru lub z niego wychodzi.

Krok 1. Zapobieganie wczytywaniu filmu na początku

Aby wczytywać iframe filmu z opóźnieniem, musisz najpierw uniemożliwić jego wczytywanie w zwykły sposób. Aby to zrobić, zastąp atrybut src atrybutem data-src, aby podać 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ę, o ile zaczyna się od „data-”.

Element iframe bez atrybutu src się nie załaduje.

Krok 2. Użyj Intersection Observer do leniwego wczytywania filmu

Aby wczytać film, gdy użytkownik przewinie do niego, musisz wiedzieć, kiedy to nastąpi. Właśnie w tym miejscu przydaje się interfejs Intersection Observer API. Interfejs Intersection Observer API umożliwia zarejestrowanie funkcji wywołania zwrotnego, która jest wykonywana, gdy element, który chcesz śledzić, wchodzi do widoku lub z niego wychodzi.

Aby rozpocząć, utwórz nowy plik o nazwie 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 pliku lazy-load.js utwórz nową funkcję IntersectionObserver i przekaż jej funkcję wywołania zwrotnego do wykonania:

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

Teraz podaj observer element docelowy do obejrzenia (w tym przypadku 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 sam obiekt IntersectionObserver. Każdy wpis zawiera element target oraz właściwości opisujące jego wymiary, położenie, czas wejścia do widoku i inne informacje. Jedną z właściwości IntersectionObserverEntry jest isIntersecting – wartość logiczna, która jest równa true, gdy element wchodzi do widocznego obszaru.

W tym przykładzie target to iframe. isIntersecting jest równe true, gdy target znajdzie się w widocznym obszarze. 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 kliknij Pełny ekranpełny ekran.
  2. Aby otworzyć Narzędzia dla programistów, naciśnij `Control+Shift+J` (lub `Command+Option+J` na Macu).
  3. Kliknij kartę Konsola.

Spróbuj przewinąć 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. Ta wymiana powoduje wczytanie filmu. Następnie, gdy film zostanie załadowany, wywołaj metodę unobserve elementu observer, aby zatrzymać odtwarzanie 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 sprawdzić, 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 wygenerowała tylko 260 KB. To znaczna poprawa.

Przewiń stronę w dół i obserwuj panel Sieć. Gdy przejdziesz do filmu, zobaczysz, że strona powoduje wysyłanie dodatkowych żądań.

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

Opóźniłeś/opóźniłaś wczytywanie niekrytycznych skryptów JavaScript i wykorzystałeś/wykorzystałaś opóźnione wczytywanie żądań do YouTube, więc nadszedł czas na optymalizację pozostałych treści innych firm.

Dodanie atrybutu rel=preconnect do linku powoduje, że przeglądarka nawiązuje połączenie z domeną przed wysłaniem żądania dotyczącego tego zasobu. Ten atrybut najlepiej używać w przypadku źródeł, które udostępniają 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 wcześniejsze połączenia ze 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 z opóźnieniem, pozostaje tylko staticxx.facebook.com, czyli źródło widżetu udostępniania w mediach społecznościowych. Utworzenie wstępnego połączenia z tą domeną jest tak proste, jak dodanie tagu <link> do <head> w dokumentie:

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

Ponowna ocena skuteczności

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 czas FCP wynoszący 1 s i wynik dotyczący wydajności o wysokości 99.