Na konferencji Google IO 2018 przedstawiliśmy przegląd narzędzi, bibliotek i technik optymalizacji, które ułatwiają poprawę wydajności witryn internetowych. Tutaj wyjaśniamy je na przykładzie aplikacji The Oodles Theater. Omawiamy też nasze eksperymenty z wczytywaniem predykcyjnym i nową inicjatywę Guess.js.
W ciągu ostatniego roku sporo czasu poświęciliśmy na szukanie sposobów na przyspieszenie i zwiększenie wydajności internetu. W efekcie powstały nowe narzędzia, metody i biblioteki, o których chcemy Ci opowiedzieć w tym artykule. W pierwszej części pokażemy Ci kilka technik optymalizacji, których używaliśmy w praktyce podczas tworzenia aplikacji Oodles Theater. W drugiej części opowiemy o naszych eksperymentach z wczytywaniem predykcyjnym i nowej inicjatywie Guess.js.
Potrzebna wydajność
Internet staje się coraz cięższy. Jeśli sprawdzimy stan internetu, okaże się, że średnia strona mobilna waży około 1,5 MB, z czego większość to JavaScript i obrazy.
Rosnący rozmiar stron internetowych wraz z innymi czynnikami, takimi jak opóźnienia w sieci, ograniczenia procesora, wzorce blokujące renderowanie czy zbędny kod zewnętrzny, przyczyniają się do złożoności problemu wydajności.
Większość użytkowników twierdzi, że szybkość jest na samym szczycie hierarchii potrzeb związanych z UX. Nie jest to zbyt zaskakujące, ponieważ nie można zrobić zbyt wiele, dopóki strona się nie wczyta. Nie możesz wyciągać wartości z tej strony ani podziwiać jej estetyki.
Wiemy, że skuteczność ma znaczenie dla użytkowników, ale czasami trudno jest odkryć, od czego zacząć optymalizację. Na szczęście istnieją narzędzia, które mogą Ci w tym pomóc.
Lighthouse – podstawa procesu związanego z wydajnością
Lighthouse to część Narzędzi deweloperskich w Chrome, która umożliwia przeprowadzenie audytu witryny i podpowiada, jak ją ulepszyć.
Niedawno udostępniliśmy kilka nowych audytów wydajności, które są bardzo przydatne w codziennej pracy programisty.
Zobaczmy, jak można z nich korzystać na przykładzie aplikacji Oodles Theater. To mała demonstracyjna aplikacja internetowa, w której możesz wypróbować niektóre z naszych ulubionych interaktywnych Doodle Google, a nawet zagrać w kilka gier.
Podczas tworzenia aplikacji zależało nam na tym, aby była ona jak najbardziej wydajna. Punktem wyjścia dla optymalizacji był raport Lighthouse.
Początkowa wydajność naszej aplikacji, jaką odnotowaliśmy w raporcie Lighthouse, była dość słaba. W sieci 3G użytkownik musiał czekać 15 sekund na pierwszą znaczącą aktualizację lub na to, aż aplikacja stanie się interaktywna. Lighthouse wskazał mnóstwo problemów z naszą witryną, a ogólna ocena skuteczności 23 to właśnie odzwierciedlenie tych problemów.
Strona ważyła około 3,4 MB – musieliśmy więc pozbyć się zbędnych elementów.
To było nasze pierwsze wyzwanie związane z wydajnością: znalezienie elementów, które można łatwo usunąć bez wpływu na ogólne wrażenia.
Możliwości optymalizacji skuteczności
Usuwanie niepotrzebnych zasobów
Są pewne oczywiste elementy, które można bezpiecznie usunąć: spacje i komentarze.
Lighthouse wskazuje tę możliwość w kontroli nieskompresowanego kodu CSS i JavaScriptu. Do procesu kompilacji używaliśmy webpacka, więc w celu minifikacji po prostu użyliśmy wtyczki Uglify JS.
Kompilacja jest częstym zadaniem, dlatego powinno być możliwe znalezienie gotowego rozwiązania dla dowolnego procesu kompilacji.
Inną przydatną kontrolą w tej sekcji jest Włącz kompresję tekstu. Nie ma powodu, aby wysyłać skompresowane pliki, a większość CDN obsługuje obecnie takie pliki.
Nasz kod był hostowany w Firebase Hosting, a Firebase domyślnie włącza gzipowanie, więc dzięki hostowaniu kodu w przystępnej usłudze CDN otrzymaliśmy to bezpłatnie.
Chociaż gzip jest bardzo popularnym sposobem kompresji, inne mechanizmy, takie jak Zopfli i Brotli, również zyskują na popularności. Brotli jest obsługiwany w większości przeglądarek, a przed przesłaniem zasobów na serwer możesz użyć pliku binarnego, aby wstępnie skompresować zasoby.
Korzystanie z zasad dotyczących efektywnej pamięci podręcznej
Następnym krokiem było upewnienie się, że nie wysyłamy zasobów dwa razy, jeśli nie jest to konieczne.
Audyt Nieskuteczna polityka dotycząca pamięci podręcznej w Lighthouse pomógł nam zauważyć, że możemy zoptymalizować strategie dotyczące pamięci podręcznej, aby osiągnąć ten cel. Ustawienie na serwerze nagłówka max-age expiration header zapewniło, że podczas powtórnej wizyty użytkownik może ponownie użyć zasobów, które zostały wcześniej pobrane.
W idealnej sytuacji warto przechowywać w pamięci podręcznej jak najwięcej zasobów przez jak najdłuższy czas i zapewnić tokeny walidacyjne, aby można było efektywnie ponownie weryfikować zaktualizowane zasoby.
Usuwanie nieużywanego kodu
Jak dotąd usunęliśmy oczywiste części niepotrzebnego pobierania, ale co z tymi mniej oczywistymi? Na przykład nieużywany kod.
Czasami dodajemy do naszych aplikacji kod, który nie jest niezbędny. Dzieje się tak zwłaszcza wtedy, gdy pracujesz nad aplikacją przez dłuższy czas, zmienia się Twój zespół lub zależności, a czasami zostaje opuszczona biblioteka bez właściciela. Właśnie tak się stało.
Na początku do szybkiego tworzenia prototypów aplikacji używaliśmy biblioteki Material Components. Z czasem przeszliśmy na bardziej niestandardowy wygląd i w ogóle zapomnieliśmy o tej bibliotece. Na szczęście dzięki sprawdzeniu zasięgu kodu udało nam się ponownie znaleźć ten błąd w naszym pakiecie.
Statystyki pokrycia kodu możesz sprawdzić w DevTools, zarówno w przypadku czasu wykonywania, jak i czasu ładowania aplikacji. Na dolnym zrzucie ekranu widać 2 duże czerwone paski – ponad 95% nieużywanych plików CSS i spora ilość kodu JavaScript.
Lighthouse wykrył ten problem również w audycie nieużywanych reguł CSS. Wykazało to potencjalne oszczędności na poziomie ponad 400 KB. Wróciliśmy do kodu i usunęliśmy z tej biblioteki zarówno kod JavaScript, jak i CSS.
Dzięki temu pakiet CSS zmniejszył się 20-krotnie, co jest całkiem dobrym wynikiem dla małego, dwuwierszowego zatwierdzenia.
Oczywiście spowodowało to wzrost naszej skuteczności, a także znaczną poprawę czasu do interakcji.
W przypadku takich zmian samo sprawdzanie danych i wyników nie wystarczy. Usuwanie kodu nigdy nie jest pozbawione ryzyka, dlatego zawsze należy zwracać uwagę na potencjalne regresje.
Nasz kod nie był używany w 95% przypadków – nadal jest 5%. Wygląda na to, że jeden z naszych komponentów nadal używał stylów z tej biblioteki – małe strzałki na suwaku z doodle. Ponieważ była tak mała, mogliśmy ją ręcznie dodać do przycisków.
Jeśli usuniesz kod, upewnij się, że masz odpowiednią procedurę testowania, która pomoże Ci chronić się przed potencjalnymi regresjami wizualnymi.
Unikaj ogromnych obciążeń sieci
Wiemy, że duże zasoby mogą spowolnić wczytywanie stron internetowych. Mogą one kosztować naszych użytkowników pieniądze i mieć duży wpływ na ich plany danych, dlatego warto o tym pamiętać.
Lighthouse wykrył, że wystąpił problem z niektórymi danymi sieciowymi, korzystając z audytu Enormous network payload.
W tym przypadku mieliśmy ponad 3 MB kodu, który był przesyłany. To całkiem sporo, zwłaszcza na urządzeniach mobilnych.
Na samym szczycie tej listy Latarnia wskazała, że mamy pakiet dostawcy JavaScripta, który zajmuje 2 MB nieskompresowanego kodu. Jest to też problem podkreślony przez webpack.
Jak to mówią: najszybsze żądanie to takie, którego nie wysłano.
W idealnej sytuacji powinieneś mierzyć wartość każdego zasobu, który udostępniasz użytkownikom, mierzyć jego skuteczność i decydowować, czy warto go udostępnić w ramach początkowego wrażenia. Czasami te zasoby mogą być opóźnione lub ładowane leniwie albo przetwarzane w czasie bezczynności.
W naszym przypadku mieliśmy do czynienia z wiele pakietami JavaScript, więc mieliśmy szczęście, ponieważ społeczność JavaScript ma bogaty zestaw narzędzi do sprawdzania pakietów JavaScript.
Najpierw użyliśmy narzędzia webpack bundle analyzer, które poinformowało nas, że zawieramy zależność o nazwie unicode, która zajmuje 1,6 MB przeanalizowanego kodu JavaScriptu, czyli całkiem sporo.
Następnie otworzyliśmy edytor i za pomocą wtyczki Import Cost Plugin for Visual Code udało nam się zwizualizować koszt każdego importowanego modułu. Dzięki temu mogliśmy sprawdzić, który komponent zawiera kod odwołujący się do tego modułu.
Następnie przełączyliśmy się na inne narzędzie, BundlePhobia. To narzędzie umożliwia wpisanie nazwy dowolnego pakietu NPM i zobaczenie szacowanego rozmiaru zminiaturyzowanego i spakowanego archiwum. Znaleźliśmy świetną alternatywę dla używanego przez nas modułu slug, który ważył tylko 2,2 KB, więc go zastąpiliśmy.
Miało to duży wpływ na naszą skuteczność. Dzięki tej zmianie i innym odkrytom udało nam się zmniejszyć rozmiar pakietu JavaScriptu o 2, 1 MB.
Po uwzględnieniu rozmiaru tych pakietów po skompresowaniu i zminimalizowaniu zauważyliśmy ogólny wzrost o 65%. Okazało się, że warto było wdrożyć ten proces.
Dlatego staraj się, aby w swoich witrynach i aplikacjach nie było niepotrzebnych plików do pobrania. Przeprowadzenie inwentaryzacji komponentów i zmierzenie ich wpływu na skuteczność może mieć naprawdę ogromne znaczenie, dlatego pamiętaj, aby regularnie przeprowadzać audyt komponentów.
Skrócenie czasu uruchamiania JavaScriptu dzięki dzieleniu kodu
Duże ładunki sieciowe mogą mieć duży wpływ na aplikację, ale jest jeszcze coś, co może mieć naprawdę duży wpływ, a jest to JavaScript.
JavaScript to najdroższy komponent. Jeśli na urządzeniu mobilnym wysyłasz duże pakiety kodu JavaScript, może to opóźnić czas, po którym użytkownicy będą mogli wchodzić w interakcję z elementami interfejsu. Oznacza to, że mogą klikać elementy interfejsu, ale nic istotnego się nie stanie. Dlatego ważne jest, abyśmy zrozumieli, dlaczego kod JavaScript jest tak drogi.
W ten sposób przeglądarka przetwarza JavaScript.
Najpierw musimy pobrać skrypt. Mamy silnik JavaScript, który musi przeanalizować kod, skompilować go i wykonać.
Te fazy nie zajmują dużo czasu na zaawansowanym urządzeniu, takim jak komputer stacjonarny czy laptop, a czasem nawet na zaawansowanym telefonie. Jednak na przeciętnym telefonie komórkowym ten proces może potrwać od 5 do 10 razy dłużej. To opóźnia interaktywność, dlatego ważne jest, abyśmy spróbowali skrócić ten czas.
Aby ułatwić Ci wykrywanie tych problemów w aplikacji, wprowadziliśmy w Lighthouse nowy audyt czasu uruchamiania JavaScriptu.
W przypadku aplikacji Oodle zajęło to 1, 8 sekundy. Okazało się, że importowaliśmy statycznie wszystkie nasze ścieżki i składniki do jednego monolitycznego pakietu JavaScript.
Jednym ze sposobów obejścia tego ograniczenia jest podział kodu.
Dzielenie kodu polega na tym, że zamiast dostarczać użytkownikom całej pizzy w postaci kodu JavaScript, dostarczasz im tylko 1 kawałek naraz, gdy tego potrzebują.
Podział kodu można zastosować na poziomie trasy lub komponentu. Świetnie współpracuje z React i React Loadable, Vue.js, Angular, Polymer, Preact i wieloma innymi bibliotekami.
Wprowadziliśmy w naszej aplikacji podział kodu, przechodząc z importu statycznego na import dynamiczny, co pozwoliło nam asynchronicznie wczytywać kod w miarę potrzeby.
Dzięki temu udało nam się zmniejszyć rozmiar pakietów, a także skrócić czas uruchamiania kodu JavaScript. Czas ten skrócono do 0,78 sekund, co oznacza, że aplikacja działa o 56% szybciej.
Jeśli tworzysz treści, które wymagają dużej ilości kodu JavaScript, pamiętaj, aby wysyłać użytkownikowi tylko kod, którego potrzebuje.
Korzystaj z takich koncepcji jak dzielenie kodu i sprawdzaj repozytorium webpack-libs-optimizations, aby dowiedzieć się, jak zmniejszyć rozmiar biblioteki, jeśli używasz webpacka.
Zoptymalizuj obrazy
W aplikacji Oodle używamy wielu obrazów. Niestety Lighthouse był znacznie mniej entuzjastyczny niż my. W zasadzie nie udało nam się przejść wszystkich 3 sprawdzeń dotyczących obrazów.
Nie zoptymalizowaliśmy obrazów, nie ustawiliśmy ich prawidłowego rozmiaru i mogliśmy uzyskać lepsze wyniki, gdybyśmy użyli innych formatów obrazów.
Zaczęliśmy od optymalizacji obrazów.
W przypadku pojedynczej optymalizacji możesz użyć narzędzi wizualnych, takich jak ImageOptim czy XNConvert.
Bardziej zautomatyzowanym podejściem jest dodanie do procesu kompilacji kroku optymalizacji obrazów za pomocą bibliotek takich jak imagemin.
Dzięki temu obrazy dodane w przyszłości będą automatycznie optymalizowane. Niektóre sieci CDN, np. Akamai, oraz rozwiązania innych firm, takie jak Cloudinary, Fastly czy Uploadcare, oferują kompleksowe rozwiązania do optymalizacji obrazów. Możesz też po prostu hostować swoje obrazy w tych usługach.
Jeśli nie chcesz tego robić ze względu na koszty lub problemy z opóźnieniem, możesz skorzystać z alternatywnych rozwiązań hostowanych lokalnie, takich jak Thumbor czy Imageflow.
Nasz obraz tła PNG został oznaczony w webpack jako duży, i słusznie. Po prawidłowym dopasowaniu go do obszaru widocznego i przesłaniu do ImageOptim zmniejszyliśmy rozmiar do 100 KB, co jest do przyjęcia.
Powtórzenie tego procesu w przypadku wielu obrazów w naszej witrynie pozwoliło nam znacznie zmniejszyć całkowitą wagę strony.
Używanie odpowiedniego formatu dla treści animowanych
GIF-y mogą być naprawdę drogie. Co zaskakujące, format GIF nigdy nie był przeznaczony do tworzenia animacji. Dlatego przejście na bardziej odpowiedni format wideo pozwoli Ci znacznie zmniejszyć rozmiar pliku.
W aplikacji Oodle używaliśmy GIF-a jako sekwencji wprowadzającej na stronie głównej. Według Lighthouse możemy zaoszczędzić ponad 7 MB, przechodząc na bardziej wydajny format wideo. Nasz klip ważył około 7,3 MB, czyli zdecydowanie za dużo jak na potrzeby zwykłej witryny, więc zamiast tego przekształciliśmy go w element wideo z 2 plikami źródłowymi – mp4 i WebM, aby zapewnić większą obsługę przez przeglądarki.
Użyliśmy narzędzia FFmpeg, aby przekonwertować animowany GIF na plik mp4. Format WebM pozwala na jeszcze większe oszczędności – interfejs API ImageOptim może przeprowadzić taką konwersję za Ciebie.
ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4
Dzięki tej konwersji udało nam się zmniejszyć ogólną wagę o ponad 80%. Dzięki temu udało nam się zmniejszyć rozmiar pliku do około 1 MB.
Mimo to 1 MB to duża ilość danych, zwłaszcza dla użytkownika z ograniczoną przepustowością. Na szczęście mogliśmy użyć interfejsu Effective Type API, aby wykryć, że użytkownicy mają wolne łącze, i zamiast tego wyświetlić im znacznie mniejszy plik JPEG.
Ten interfejs używa skutecznego czasu pętli i wartości downing do oszacowania typu sieci, z której korzysta użytkownik. Zwraca on po prostu ciąg znaków: slow 2G, 2G, 3G lub 4G. W zależności od tej wartości, jeśli użytkownik korzysta z mniej niż 4G, możemy zastąpić element wideo obrazem.
if (navigator.connection.effectiveType) { ... }
W pewnym stopniu ogranicza to wygodę korzystania, ale przynajmniej strona jest dostępna przy wolnym połączeniu.
Leniwe ładowanie obrazów poza ekranem
Karuzele, suwaki i bardzo długie strony często wczytują obrazy, mimo że użytkownik nie może ich od razu zobaczyć na stronie.
Lighthouse odnotuje to zachowanie w audycie obrazów poza ekranem, a możesz je też zobaczyć w panelu sieci w Narzędziach dla programistów. Jeśli widzisz wiele obrazów, a na stronie widocznych jest tylko kilka z nich, być może warto rozważyć ich wczytywanie opóźnione.
Łagodne wczytywanie nie jest jeszcze obsługiwane w standardzie w przeglądarce, więc musimy użyć JavaScriptu, aby dodać tę funkcję. Aby dodać do okładek Oodle funkcję leniwego wczytywania, użyliśmy biblioteki Lazysizes.
<!-- Import library -->
import lazysizes from 'lazysizes' <!-- or -->
<script src="lazysizes.min.js"></script>
<!-- Use it -->
<img data-src="image.jpg" class="lazyload"/>
<img class="lazyload"
data-sizes="auto"
data-src="image2.jpg"
data-srcset="image1.jpg 300w,
image2.jpg 600w,
image3.jpg 900w"/>
Lazysizes jest inteligentny, ponieważ nie tylko śledzi zmiany widoczności elementu, ale też proaktywnie pobiera z wyprzedzeniem elementy, które znajdują się w pobliżu widoku, aby zapewnić użytkownikom optymalne wrażenia.
Zapewnia ona też opcjonalną integrację z usługą IntersectionObserver
, która umożliwia bardzo wydajne wyszukiwanie widoczności.
Po tej zmianie nasze obrazy są pobierane na żądanie. Jeśli chcesz dowiedzieć się więcej na ten temat, odwiedź stronę images.guide – to bardzo przydatne i wyczerpujące źródło informacji.
Pomoc w szybszym dostarczaniu przez przeglądarkę kluczowych zasobów
Nie wszystkie bajty przesyłane do przeglądarki mają ten sam stopień ważności, a przeglądarka o tym wie. Wiele przeglądarek korzysta z heurystyki, aby określić, co pobrać w pierwszej kolejności. Czasami pobierają one pliki CSS przed obrazami lub skryptami.
Coś, co może być przydatne, to my, autorzy strony, informujący przeglądarkę, co jest dla nas naprawdę ważne. Na szczęście w ostatnich latach dostawcy przeglądarek dodali kilka funkcji, które nam w tym pomagają, np. wskazówki dotyczące zasobów, takie jak link rel=preconnect
, preload
lub prefetch
.
Te możliwości, które zostały udostępnione na platformie internetowej, pomagają przeglądarce pobierać odpowiednie dane we właściwym czasie. Mogą one być nieco wydajniejsze niż niektóre niestandardowe metody wczytywania oparte na logice, które są wykonywane za pomocą skryptu.
Zobaczmy, jak Lighthouse pomaga nam skutecznie korzystać z tych funkcji.
Pierwszą rzeczą, którą Lighthouse zaleca, jest unikanie wielokrotnych kosztownych podróży powrotnych do dowolnego miejsca pochodzenia.
W przypadku aplikacji Oodle bardzo często korzystamy z czcionek Google Fonts. Gdy dodasz do strony arkusz stylów Google Fonts, zostanie on połączony z 2 subdomenami. Lighthouse informuje, że jeśli uda nam się rozgrzać to połączenie, możemy skrócić czas początkowego nawiązywania połączenia nawet o 300 milisekund.
Korzystając z linku rel preconnect, możemy skutecznie ukryć opóźnienie połączenia.
Szczególnie w przypadku Google Fonts, gdzie pliki czcionek CSS są hostowane na stronie googleapis.com, a zasobów czcionek na stronie Gstatic, może to mieć bardzo duży wpływ. Po zastosowaniu tej optymalizacji udało nam się skrócić czas o kilkaset milisekund.
Kolejna rzecz, którą sugeruje Lighthouse, to wstępne wczytywanie kluczowych żądań.
<link rel=preload>
jest bardzo wydajny. Informuje przeglądarkę, że zasób jest potrzebny w ramach bieżącej nawigacji, i próbuje jak najszybciej pobrać go z przeglądarki.
Lighthouse informuje nas, że powinniśmy wstępnie wczytać najważniejsze zasoby czcionek internetowych, ponieważ wczytujemy 2 czcionki internetowe.
Wczytywanie w czcionce internetowej wygląda tak: określasz rel=preload
, przekazujesz as
z typem czcionki, a następnie określasz typ czcionki, którą próbujesz załadować, np. woff2.
Może to mieć poważny wpływ na Twoją stronę.
Jeśli czcionki internetowe są kluczowe dla Twojej strony, a nie używasz atrybutu rel preload w linku, przeglądarka musi najpierw pobrać kod HTML, przeanalizować kod CSS, a dopiero potem pobrać czcionki internetowe.
Dzięki atrybucie link rel preload przeglądarka może zacząć pobierać te czcionki internetowe znacznie wcześniej, gdy tylko przeanalizuje kod HTML. W przypadku naszej aplikacji udało nam się w ten sposób skrócić czas potrzebny na renderowanie tekstu za pomocą czcionek internetowych o 1 sekundę.
Jeśli chcesz wczytywać czcionki za pomocą Google Fonts, nie jest to tak proste.
Adresy URL czcionek Google, które podajemy w naszych stylach w przypadku czcionek, są dość regularnie aktualizowane przez zespół ds. czcionek. Te adresy URL mogą wygasnąć lub zostać zaktualizowane w regularnych odstępach czasu. Dlatego, jeśli chcesz mieć pełną kontrolę nad wczytywaniem czcionek, zalecamy samodzielne hostowanie czcionek internetowych. Może to być bardzo przydatne, ponieważ daje Ci dostęp do takich funkcji jak wstępny wczytywanie linków.
W naszym przypadku bardzo przydatne okazało się narzędzie Google Web Fonts Helper, które pomogło nam w pracy offline z tymi czcionkami internetowymi i ich konfiguracji na komputerze.
Niezależnie od tego, czy używasz czcionek internetowych jako kluczowych zasobów, czy też są to zasoby JavaScript, postaraj się pomóc przeglądarce w jak najszybszym wczytaniu tych zasobów.
Experimental: Priority Hints
Mamy coś specjalnego do przekazania. Oprócz funkcji takich jak wskazówki dotyczące zasobów i wstępny odczyt, pracowaliśmy nad zupełnie nową eksperymentalną funkcją przeglądarki, którą nazywamy wskazówkami priorytetowymi.
To nowa funkcja, która pozwala zasugerować przeglądarce, jak ważny jest zasób. Wyświetla nowy atrybut – „Ważność” – z wartościami „Niski”, „Wysoki” lub „Automatycznie”.
Dzięki temu możemy obniżyć priorytet mniej ważnych zasobów, takich jak niekrytyczne style, obrazy czy wywołania interfejsu API, aby zmniejszyć rywalizację. Możemy też zwiększyć priorytet ważnych elementów, takich jak obrazy główne.
W przypadku naszej aplikacji Oodle to doprowadziło do jednego praktycznego miejsca, w którym mogliśmy wprowadzić optymalizację.
Zanim dodaliśmy do obrazów ładowanie opóźnione, przeglądarka pobierała wszystkie obrazy z karuzeli z doodle, przypisując im wysoki priorytet. Niestety, dla użytkownika najważniejsze były zdjęcia w środku karuzeli. W związku z tym ustawiliśmy priorytet tych obrazów tła na bardzo niski, a tych na pierwszym planie – na bardzo wysoki. Dzięki temu udało nam się uzyskać 2 sekundy oszczędności na wolnym łączu 3G oraz skrócić czas pobierania i renderowania tych obrazów. To bardzo pozytywne doświadczenie.
Mamy nadzieję, że w ciągu kilku tygodni udostępnimy tę funkcję w wersji Canary.
mieć strategię wczytywania czcionek internetowych;
Typografia jest podstawą dobrego projektu. Jeśli używasz czcionek internetowych, nie blokuj renderowania tekstu i nie wyświetlaj niewidocznego tekstu.
Wskazujemy na to w Lighthouse za pomocą audytu Unikaj niewidocznego tekstu podczas wczytywania czcionek internetowych.
Jeśli wczytujesz czcionki internetowe za pomocą bloku czcionek, pozwalasz przeglądarce decydować, co zrobić, jeśli wczytywanie czcionki internetowej zajmuje dużo czasu. Niektóre przeglądarki czekają na to do 3 sekund, po czym przełączają się na czcionkę systemową, a potem zastępują ją czcionką pobieraną z sieci.
Staramy się unikać tego niewidocznego tekstu, więc w tym przypadku nie zobaczylibyśmy klasycznych doodle'ów z tego tygodnia, gdyby czcionka internetowa zajęła zbyt dużo czasu. Na szczęście dzięki nowej funkcji font-display
masz znacznie większą kontrolę nad tym procesem.
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-display: swap;
font-weight: 400;
src: local('Montserrat Regular'), local('Montserrat-Regular'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('montserrat-v12-latin-regular.woff2') format('woff2'),
/* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
url('montserrat-v12-latin-regular.woff') format('woff');
}
Wyświetlanie czcionek pozwala określić, jak czcionki internetowe będą renderowane lub zastępowane na podstawie czasu ich przełączania.
W tym przypadku używamy wymiany wyświetlania czcionki. Swap nadaje czcionce okres blokowania równy 0 sekund i nieskończony okres przełączania. Oznacza to, że przeglądarka wyświetli tekst niemal natychmiast za pomocą czcionki zastępczej, jeśli wczytywanie czcionki zajmie trochę czasu. Gdy będzie ona dostępna, zostanie ona zastąpiona.
W przypadku naszej aplikacji było to świetne, ponieważ pozwoliło nam wyświetlać tekst już na bardzo wczesnym etapie i przełączyć się na czcionkę internetową, gdy tylko będzie gotowa.
Jeśli używasz czcionek internetowych, tak jak większość użytkowników internetu, zastosuj dobrą strategię wczytywania czcionek internetowych.
Istnieje wiele funkcji platformy internetowej, których możesz używać do optymalizacji wczytywania czcionek. Zapoznaj się też z repozytorium Web Font Recipes Zacha Leathermana, ponieważ jest ono naprawdę świetne.
Ogranicz skrypty blokujące renderowanie
Są też inne części aplikacji, które możemy przesunąć do wcześniejszego etapu łańcucha pobierania, aby zapewnić użytkownikom przynajmniej podstawowe funkcje.
Na pasku czasowym Lighthouse widać, że przez pierwsze kilka sekund, gdy wczytują się wszystkie zasoby, użytkownik nie widzi żadnych treści.
Pobieranie i przetwarzanie zewnętrznych arkuszy stylów uniemożliwia nam dalszy postęp w procesie renderowania.
Możemy spróbować zoptymalizować ścieżkę renderowania krytycznego, przekazując niektóre style nieco wcześniej.
Jeśli wyodrębnimy style odpowiedzialne za to wstępne renderowanie i umieścimy je w kod HTML, przeglądarka będzie mogła je od razu renderować bez czekania na zewnętrzne arkusze stylów.
W naszym przypadku użyliśmy modułu NPM o nazwie Critical, aby wbudować kluczowe treści w pliku index.html podczas kompilacji.
Chociaż ten moduł wykonał większość ciężkiej pracy za nas, nadal było trochę trudniej sprawić, aby działał płynnie na różnych trasach.
Jeśli nie będziesz uważać lub struktura witryny będzie bardzo złożona, wprowadzenie tego typu wzoru może być bardzo trudne, jeśli od początku nie zaplanowano architektury powłoki aplikacji.
Dlatego tak ważne jest, aby już na wczesnym etapie zwracać uwagę na skuteczność. Jeśli od razu nie zadbasz o wydajność, później możesz mieć z tym problemy.
Ostatecznie ryzyko się opłaciło, udało nam się to zrobić, a aplikacja zaczęła wyświetlać treści znacznie wcześniej, co znacznie skróciło czas pierwszego wyrenderowania elementu znaczącego.
Wynik
To była długa lista optymalizacji skuteczności, które zastosowaliśmy w naszej witrynie. Zobaczmy wynik. Oto czas wczytywania naszej aplikacji na średnim urządzeniu mobilnym w sieci 3G przed optymalizacją i po niej.
Wynik wydajności Lighthouse wzrósł z 23 na 91. To całkiem dobry postęp pod względem szybkości. Wszystkie zmiany zostały wprowadzone dzięki ciągłemu sprawdzaniu i stosowaniu się do raportu Lighthouse. Jeśli chcesz sprawdzić, jak technicznie wdrożyliśmy wszystkie ulepszenia, zapoznaj się z naszym repozytorium, zwłaszcza z przesłanymi tam PR-ami.
Prognozowanie wydajności – tworzenie doświadczeń użytkowników na podstawie danych
Jesteśmy przekonani, że systemy uczące się to ekscytująca przyszłość w wielu dziedzinach. Mamy nadzieję, że w przyszłości więcej eksperymentów będzie się opierać na prawdziwych danych, które mogą naprawdę wpływać na wrażenia użytkowników.
Obecnie podejmujemy wiele arbitralnych decyzji dotyczących tego, czego użytkownik może chcieć lub czego może potrzebować, a także tego, co warto pobrać z poziomu pamięci podręcznej lub podręcznej. Jeśli zgadniemy, możemy nadać priorytet niewielkiej liczbie zasobów, ale trudno jest to zastosować do całej witryny.
Mamy już dostępne dane, które pozwalają nam lepiej optymalizować wyniki. Dzięki interfejsowi Google Analytics Reporting API możemy sprawdzić, które strony i adresy URL w naszej witrynie mają najwyższy współczynnik odrzuceń. Na tej podstawie możemy wyciągać wnioski o tym, które zasoby powinny być priorytetowe.
Jeśli połączymy to z dobrym modelem prawdopodobieństwa, unikniemy marnowania danych użytkownika przez agresywne nadmierne pobieranie treści. Możemy wykorzystać te dane Google Analytics oraz uczenie maszynowe i modele, takie jak łańcuchy Markowa czy sieci neuronowe, aby wdrażać takie modele.
Aby ułatwić przeprowadzanie tych eksperymentów, ogłaszamy nową inicjatywę o nazwie Guess.js.
Guess.js to projekt skupiający się na wrażeniach użytkowników w internecie, które są oparte na danych. Mamy nadzieję, że zainspiruje on do korzystania z danych dostępnych w Google Analytics do poprawy wydajności witryny i nie tylko. Wszystkie te narzędzia są dostępne na GitHubie jako oprogramowanie open source. Ta funkcja została opracowana we współpracy z komunitą open source przez Minko Gecheva, Kyle’a Matthewsa z Gatsby, Katie Hempenius i kilku innych osób.
Sprawdź Guess.js i powiedz nam, co o nim myślisz.
Podsumowanie
Wyniki i dane pomagają zwiększać szybkość działania stron internetowych, ale są one tylko środkiem, a nie celem samym w sobie.
Wszyscy znamy to uczucie, gdy strona wczytuje się wolno, ale teraz mamy możliwość zapewnienia użytkownikom szybszego wczytywania stron.
Poprawianie wydajności to proces. Wiele drobnych zmian może przynieść duże korzyści. Korzystając z odpowiednich narzędzi do optymalizacji i śledząc raporty Lighthouse, możesz zapewnić użytkownikom lepsze i bardziej wszechstronne wrażenia.
Szczególne podziękowania dla: Warda Peetersa, Minko Gecheva, Kyle’a Mathewsa, Katie Hempenius, Doma Farolina, Yoava Weissa, Susie Lu, Yusuke Utsunomiya, Toma Ankersa, Lighthouse i Google Doodles.