Na konferencji Google IO 2018 przedstawiliśmy zestawienie narzędzi, bibliotek i technik optymalizacji, które ułatwiają poprawę wydajności witryn. Wyjaśniamy je na przykładzie aplikacji The Oodles Theater. Opisujemy też nasze eksperymenty z predykcyjnym wczytywaniem i nową inicjatywę Guess.js.
W ciągu ostatniego roku intensywnie pracowaliśmy nad tym, jak przyspieszyć i usprawnić działanie internetu. Dzięki temu powstały nowe narzędzia, podejścia i biblioteki, którymi chcemy się z Tobą podzielić w tym artykule. W pierwszej części pokażemy Ci techniki optymalizacji, których użyliśmy w praktyce podczas tworzenia aplikacji Oodles Theater. W drugiej części opowiemy o naszych eksperymentach z wczytywaniem predykcyjnym i nowej inicjatywie Guess.js.
Potrzeba wydajności
Internet z roku na rok staje się coraz bardziej obciążony. Jeśli sprawdzimy stan internetu, zobaczymy, że średnia strona na urządzeniu mobilnym waży około 1,5 MB, a większość tej wagi stanowią JavaScript i obrazy.
Rosnący rozmiar stron internetowych wraz z innymi czynnikami, takimi jak opóźnienie sieci, ograniczenia procesora, wzorce blokujące renderowanie czy zbędny kod zewnętrzny, przyczynia się do złożoności problemu wydajności.
Większość użytkowników uważa szybkość za najważniejszy element UX. Nie jest to zaskakujące, ponieważ dopóki strona nie zostanie wczytana, nie można na niej wiele zrobić. Nie możesz czerpać wartości ze strony ani podziwiać jej estetyki.
Wiemy, że wydajność jest ważna dla użytkowników, ale może się wydawać, że odkrycie, od czego zacząć optymalizację, jest tajemnicą. Na szczęście istnieją narzędzia, które mogą Ci w tym pomóc.
Lighthouse – podstawa przepływu pracy związanego z wydajnością
Lighthouse to część Narzędzi deweloperskich w Chrome, która umożliwia przeprowadzenie audytu witryny i uzyskanie wskazówek, jak ją ulepszyć.
Niedawno udostępniliśmy wiele nowych testów wydajności, które są bardzo przydatne w codziennym procesie tworzenia aplikacji.
Przyjrzyjmy się, jak możesz z nich korzystać na praktycznym przykładzie: aplikacji Oodles Theater. Jest to mała demonstracyjna aplikacja internetowa, w której możesz wypróbować niektóre z naszych ulubionych interaktywnych Google Doodles, a nawet zagrać w jedną lub dwie gry.
Podczas tworzenia aplikacji zależało nam na tym, aby działała jak najwydajniej. Punktem wyjścia do optymalizacji był raport Lighthouse.
Początkowa wydajność naszej aplikacji, widoczna w raporcie Lighthouse, była dość słaba. W sieci 3G użytkownik musiał czekać 15 sekund na pierwsze znaczące wyrenderowanie lub na możliwość interakcji z aplikacją. Lighthouse wykrył wiele problemów z naszą witryną, a ogólny wynik wydajności wynoszący 23 odzwierciedlał ten stan.
Strona ważyła około 3,4 MB, więc musieliśmy ją odchudzić.
To był początek naszego pierwszego wyzwania związanego z wydajnością: znalezienie elementów, które możemy łatwo usunąć bez wpływu na ogólne wrażenia.
Możliwości optymalizacji skuteczności
Usuwanie niepotrzebnych zasobów
Istnieją oczywiste elementy, które można bezpiecznie usunąć: białe znaki i komentarze.
Lighthouse zwraca na to uwagę w kontroli niezminimalizowanego kodu CSS i JavaScript. Do procesu kompilacji używaliśmy webpacka, więc aby uzyskać minifikację, po prostu użyliśmy wtyczki Uglify JS.
Minifikacja to powszechne zadanie, więc powinna być dostępna gotowa funkcja dla każdego procesu kompilacji, którego używasz.
Innym przydatnym audytem w tym obszarze jest Włącz kompresję tekstu. Nie ma powodu, aby wysyłać nieskompresowane pliki, a większość sieci CDN obsługuje to obecnie od razu po wyjęciu z pudełka.
Do hostowania kodu używaliśmy Firebase Hosting, a Firebase domyślnie włącza kompresję gzip, więc dzięki hostowaniu kodu w rozsądnej sieci CDN otrzymaliśmy to bezpłatnie.
Gzip to bardzo popularny sposób kompresji, ale coraz większą popularność zyskują też inne mechanizmy, takie jak Zopfli i Brotli. Brotli jest obsługiwany przez większość przeglądarek. Możesz użyć pliku binarnego, aby wstępnie skompresować komponenty przed wysłaniem ich na serwer.
Używaj efektywnych zasad pamięci podręcznej
Kolejnym krokiem było upewnienie się, że w razie potrzeby nie wysyłamy zasobów dwukrotnie.
Audyt Nieefektywna strategia buforowania w Lighthouse pomógł nam zauważyć, że możemy zoptymalizować strategie buforowania, aby to osiągnąć. Ustawiając na naszym serwerze nagłówek wygasania max-age, zapewniliśmy, że podczas ponownej wizyty użytkownik może ponownie wykorzystać zasoby, które pobrał wcześniej.
Najlepiej jest buforować jak najwięcej zasobów w jak najbardziej bezpieczny sposób przez jak najdłuższy czas i udostępniać tokeny weryfikacyjne, aby skutecznie ponownie weryfikować zaktualizowane zasoby.
Usuwanie nieużywanego kodu
Usunęliśmy już oczywiste części niepotrzebnego pobierania, ale co z mniej oczywistymi? Może to być na przykład nieużywany kod.
Czasami w naszych aplikacjach umieszczamy kod, który nie jest tak naprawdę potrzebny. Dzieje się tak zwłaszcza wtedy, gdy pracujesz nad aplikacją przez dłuższy czas, Twój zespół lub zależności ulegają zmianie, a czasami pozostaje biblioteka bez powiązań. Właśnie to nam się przydarzyło.
Na początku korzystaliśmy z biblioteki Material Components, aby szybko stworzyć prototyp aplikacji. Z czasem przeszliśmy na bardziej spersonalizowany wygląd i zapomnieliśmy o tej bibliotece. Na szczęście sprawdzanie pokrycia kodu pomogło nam ponownie odkryć ten kod w naszym pakiecie.
Statystyki pokrycia kodu możesz sprawdzić w Narzędziach deweloperskich zarówno w przypadku czasu działania, jak i czasu wczytywania aplikacji. Na zrzucie ekranu u dołu widać 2 duże czerwone paski. Ponad 95% naszego kodu CSS było nieużywane, podobnie jak spora część kodu JavaScript.
Lighthouse wykrył też ten problem w audycie nieużywanych reguł CSS. Wskazywał on potencjalną oszczędność ponad 400 KB. W związku z tym wróciliśmy do naszego kodu i usunęliśmy z tej biblioteki zarówno część JavaScript, jak i CSS.
Dzięki temu rozmiar pakietu CSS zmniejszył się 20-krotnie, co jest całkiem niezłym wynikiem jak na niewielką zmianę w 2 wierszach kodu.
Oczywiście wpłynęło to na wzrost naszego wyniku wydajności, a także znacznie poprawiło czas do interaktywności.
Jednak w przypadku takich zmian nie wystarczy sprawdzać tylko danych i wyników. Usuwanie rzeczywistego kodu nigdy nie jest wolne od ryzyka, dlatego zawsze należy uważać na potencjalne regresje.
Nasz kod nie był używany w 95% przypadków – gdzieś jest jeszcze te 5%. Okazało się, że jeden z naszych komponentów nadal korzystał ze stylów z tej biblioteki – małe strzałki w suwaku doodle. Ponieważ jednak była ona tak mała, mogliśmy po prostu ręcznie przywrócić te style w przyciskach.
Jeśli usuniesz kod, upewnij się, że masz odpowiedni proces testowania, który pomoże Ci zapobiec potencjalnym regresjom wizualnym.
Unikaj ogromnych pakietów danych sieciowych
Wiemy, że duże zasoby mogą spowalniać ładowanie stron internetowych. Mogą one generować koszty dla użytkowników i mieć duży wpływ na ich pakiety danych, dlatego warto o tym pamiętać.
Lighthouse wykrył, że mamy problem z niektórymi ładunkami sieciowymi, korzystając z audytu Ogromny ładunek sieciowy.
Okazało się, że wysyłamy ponad 3 MB kodu, co jest dość dużą ilością, zwłaszcza na urządzeniach mobilnych.
Na samym początku tej listy Lighthouse zwrócił uwagę, że mamy pakiet dostawcy JavaScriptu, który zawiera 2 MB nieskompresowanego kodu. Jest to również problem, na który zwraca uwagę webpack.
Jak mówi przysłowie: najszybsza prośba to ta, której nie trzeba wysyłać.
Najlepiej byłoby mierzyć wartość każdego zasobu, który udostępniasz użytkownikom, mierzyć wydajność tych zasobów i określać, czy warto je udostępniać w ramach początkowego środowiska. Czasami te komponenty mogą być odroczone lub ładowane z opóźnieniem albo przetwarzane w czasie bezczynności.
W naszym przypadku, ponieważ mamy do czynienia z wieloma pakietami JavaScript, mieliśmy szczęście, bo społeczność JavaScript ma bogaty zestaw narzędzi do audytu pakietów JavaScript.
Zaczęliśmy od analizatora pakietów webpack, który poinformował nas, że uwzględniamy zależność o nazwie unicode, która zajmowała 1,6 MB w postaci przeanalizowanego kodu JavaScript, czyli całkiem sporo.
Następnie otworzyliśmy edytor i za pomocą wtyczki Import Cost Plugin for Visual Studio Code mogliśmy wizualizować 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 przeszliśmy na inne narzędzie, BundlePhobia. To narzędzie, które pozwala wpisać nazwę dowolnego pakietu NPM i sprawdzić, jaki jest szacowany rozmiar po zminimalizowaniu i skompresowaniu. Znaleźliśmy dobrą alternatywę dla używanego przez nas modułu slug, która ważyła tylko 2,2 KB, więc ją zastosowaliśmy.
Miało to duży wpływ na nasze wyniki. Dzięki tej zmianie i odkryciu innych możliwości zmniejszenia rozmiaru pakietu JavaScript udało nam się zaoszczędzić 2, 1 MB kodu.
Po uwzględnieniu rozmiaru tych pakietów po skompresowaniu i zminimalizowaniu zauważyliśmy ogólną poprawę o 65%. Okazało się, że warto było to zrobić.
Dlatego staraj się eliminować niepotrzebne pobieranie w swoich witrynach i aplikacjach. Sporządzenie spisu komponentów i pomiar ich wpływu na skuteczność może mieć duże znaczenie, dlatego regularnie przeprowadzaj audyt komponentów.
Skróć czas uruchamiania JavaScriptu dzięki dzieleniu kodu
Chociaż duże ładunki sieciowe mogą mieć duży wpływ na naszą aplikację, istnieje jeszcze jeden czynnik, który może mieć naprawdę duży wpływ, a mianowicie JavaScript.
JavaScript to Twój najdroższy zasób. Jeśli na urządzeniach mobilnych wysyłasz duże pakiety JavaScriptu, może to opóźnić możliwość interakcji użytkowników z komponentami interfejsu. Oznacza to, że mogą klikać interfejs bez żadnego znaczącego efektu. Dlatego musimy zrozumieć, dlaczego JavaScript jest tak kosztowny.
W ten sposób przeglądarka przetwarza JavaScript.
Najpierw musimy pobrać ten skrypt. Mamy silnik JavaScript, który musi przeanalizować ten kod, skompilować go i wykonać.
Na zaawansowanych urządzeniach, takich jak komputer stacjonarny, laptop czy nawet telefon z najwyższej półki, te fazy nie trwają zbyt długo. Na przeciętnym telefonie komórkowym ten proces może trwać od 5 do 10 razy dłużej. To opóźnia interaktywność, dlatego staramy się to ograniczyć.
Aby pomóc Ci wykrywać te problemy w aplikacji, wprowadziliśmy w Lighthouse nowy test czasu uruchamiania JavaScriptu.
W przypadku aplikacji Oodle dowiedzieliśmy się, że na uruchomienie JavaScriptu poświęcono 1,8 sekundy. Wszystkie nasze trasy i komponenty były importowane statycznie do jednego monolitycznego pakietu JavaScript.
Jedną z metod obejścia tego problemu jest dzielenie kodu.
Podział kodu polega na tym, że zamiast udostępniać użytkownikom całą pizzę JavaScriptu, możesz dawać im po jednym kawałku, gdy tego potrzebują.
Dzielenie kodu można zastosować na poziomie trasy lub komponentu. Działa świetnie z bibliotekami React i React Loadable, Vue.js, Angular, Polymer, Preact i wieloma innymi.
Wprowadziliśmy do naszej aplikacji podział kodu, przechodząc ze statycznych importów na importy dynamiczne, co pozwoliło nam asynchronicznie leniwie wczytywać kod w miarę potrzeb.
Dzięki temu zmniejszyliśmy rozmiar pakietów, a także skróciliśmy czas uruchamiania kodu JavaScript. Zmniejszyło to czas do 0,78 sekundy, dzięki czemu aplikacja działała o 56% szybciej.
Jeśli tworzysz aplikację, która w dużej mierze opiera się na JavaScript, wysyłaj do użytkownika tylko potrzebny mu kod.
Skorzystaj z koncepcji takich jak dzielenie kodu, poznaj pomysły takie jak usuwanie nieużywanego kodu i zapoznaj się z repozytorium webpack-libs-optimizations, aby poznać kilka pomysłów na zmniejszenie rozmiaru biblioteki, jeśli używasz webpacka.
Zoptymalizuj obrazy
W aplikacji Oodle używamy wielu obrazów. Niestety Lighthouse nie był tak entuzjastycznie nastawiony do tej zmiany jak my. W rzeczywistości nie udało nam się przejść wszystkich 3 kontroli związanych z obrazami.
Zapomnieliśmy zoptymalizować obrazy, nieprawidłowo je skalowaliśmy, a także mogliśmy zyskać na użyciu innych formatów obrazów.
Zaczęliśmy od optymalizacji obrazów.
Do jednorazowej optymalizacji możesz użyć narzędzi wizualnych, takich jak ImageOptim lub XNConvert.
Bardziej zautomatyzowane podejście polega na dodaniu do procesu kompilacji kroku optymalizacji obrazu za pomocą bibliotek takich jak imagemin.
Dzięki temu masz pewność, że obrazy dodane w przyszłości zostaną automatycznie zoptymalizowane. Niektóre sieci CDN, np. Akamai, lub rozwiązania innych firm, takie jak Cloudinary, Fastly czy Uploadcare, oferują kompleksowe rozwiązania do optymalizacji obrazów, więc możesz po prostu hostować obrazy w tych usługach.
Jeśli nie chcesz tego robić ze względu na koszty lub problemy z opóźnieniami, projekty takie jak Thumbor czy Imageflow oferują alternatywne rozwiązania do samodzielnego hostowania.
Plik PNG w tle został oznaczony w webpacku jako duży i słusznie. Po odpowiednim dopasowaniu go do widocznego obszaru i przetworzeniu za pomocą ImageOptim jego rozmiar zmniejszył się do 100 KB, co jest akceptowalne.
Powtórzenie tej czynności w przypadku wielu obrazów w naszej witrynie pozwoliło nam znacznie zmniejszyć ogólną wagę strony.
Używaj odpowiedniego formatu w przypadku treści animowanych
GIF-y mogą być bardzo drogie. Co ciekawe, format GIF nigdy nie był przeznaczony do animacji. Dlatego przejście na bardziej odpowiedni format wideo pozwala 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, co jest zbyt dużą wartością dla jakiejkolwiek rozsądnej witryny.Zamiast tego przekształciliśmy go w element wideo z 2 plikami źródłowymi – MP4 i WebM, aby zapewnić szerszą obsługę w przeglądarkach.
Do przekonwertowania animowanego GIF-a na plik MP4 użyliśmy narzędzia FFmpeg. Format WebM zapewnia jeszcze większe oszczędności. Interfejs API ImageOptim może przeprowadzić taką konwersję.
ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4
Dzięki tej konwersji udało nam się zaoszczędzić ponad 80% wagi. Dzięki temu rozmiar pliku zmniejszył się do około 1 MB.
Nawet 1 MB to duży zasób do przesłania, zwłaszcza w przypadku użytkownika z ograniczonym pasmem. Na szczęście mogliśmy użyć interfejsu Effective Type API, aby wykryć, że użytkownik ma wolne łącze, i zamiast tego przesłać mu znacznie mniejszy plik JPEG.
Ten interfejs korzysta z efektywnego czasu oczekiwania i wartości pobierania, aby oszacować typ sieci, z której korzysta użytkownik. Zwraca 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 sieci o szybkości poniżej 4G, możemy zastąpić element wideo obrazem.
if (navigator.connection.effectiveType) { ... }
Nieco pogarsza to komfort korzystania z witryny, ale przynajmniej można jej używać przy wolnym połączeniu.
Leniwe ładowanie obrazów poza ekranem
Karuzela, suwak lub bardzo długa strona często wczytują obrazy, mimo że użytkownik nie może ich od razu zobaczyć.
Lighthouse oznaczy to zachowanie w audycie obrazów poza ekranem. Możesz też sprawdzić to samodzielnie w panelu sieci Narzędzi deweloperskich. Jeśli widzisz wiele przychodzących obrazów, a tylko kilka z nich jest widocznych na stronie, możesz rozważyć wczytywanie ich na żądanie.
Leniwe wczytywanie nie jest jeszcze natywnie obsługiwane w przeglądarce, więc musimy użyć JavaScriptu, aby dodać tę funkcję. Użyliśmy biblioteki Lazysizes, aby dodać do okładek Oodle funkcję leniwego ładowania.
<!-- 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"/>
Biblioteka Lazysizes jest inteligentna, ponieważ nie tylko śledzi zmiany widoczności elementu, ale też aktywnie pobiera z wyprzedzeniem elementy, które znajdują się w pobliżu widoku, aby zapewnić optymalną wygodę użytkownika.
Oferuje też opcjonalną integrację z IntersectionObserver, która umożliwia bardzo wydajne wyszukiwanie informacji o widoczności.
Po tej zmianie obrazy są pobierane na żądanie. Jeśli chcesz dowiedzieć się więcej na ten temat, zajrzyj na stronę images.guide, która jest bardzo przydatnym i wyczerpującym źródłem informacji.
Pomóż przeglądarce w szybszym dostarczaniu kluczowych zasobów
Nie każdy bajt przesyłany do przeglądarki ma takie samo znaczenie, a przeglądarka o tym wie. Wiele przeglądarek ma heurystyki, które decydują o tym, co powinny pobrać w pierwszej kolejności. Dlatego czasami pobierają CSS przed obrazami lub skryptami.
Przydatne może być poinformowanie przeglądarki przez nas, autorów strony, o tym, co jest dla nas naprawdę ważne. Na szczęście w ciągu ostatnich kilku lat dostawcy przeglądarek dodali wiele funkcji, które nam w tym pomagają, np. wskazówki dotyczące zasobów, takie jak link rel=preconnect, preload lub prefetch.
Te funkcje wprowadzone na platformę internetową pomagają przeglądarce pobierać odpowiednie elementy we właściwym czasie i mogą być nieco bardziej wydajne niż niektóre niestandardowe podejścia oparte na logice ładowania, które są realizowane za pomocą skryptu.
Zobaczmy, jak Lighthouse pomaga nam skutecznie korzystać z niektórych z tych funkcji.
Pierwsza wskazówka Lighthouse to unikanie wielu kosztownych podróży w obie strony do dowolnego źródła.
W przypadku aplikacji Oodle intensywnie korzystamy z Google Fonts. Za każdym razem, gdy umieścisz arkusz stylów czcionek Google na stronie, połączy się on z maksymalnie 2 subdomenami. Lighthouse informuje nas, że jeśli uda nam się rozgrzać to połączenie, możemy zaoszczędzić do 300 milisekund początkowego czasu połączenia.
Korzystając z linku rel=preconnect, możemy skutecznie zamaskować opóźnienie połączenia.
Ma to duże znaczenie w przypadku usług takich jak Czcionki Google, gdzie arkusz CSS czcionki jest hostowany na googleapis.com, a zasoby czcionki na Gstatic. Zastosowaliśmy więc tę optymalizację i zaoszczędziliśmy kilkaset milisekund.
Kolejną sugestią Lighthouse jest wstępne wczytywanie żądań kluczy.
<link rel=preload> jest bardzo przydatny, ponieważ 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 wczytywać kluczowe zasoby czcionek internetowych, ponieważ wczytujemy 2 czcionki internetowe.
Wstępne wczytywanie czcionki internetowej wygląda tak: po określeniu rel=preload przekazujesz as z typem czcionki, a następnie określasz typ czcionki, którą chcesz wczytać, np. woff2.
Wpływ, jaki może to mieć na Twoją stronę, jest dość wyraźny.
Zwykle, jeśli nie używasz linku rel preload, a czcionki internetowe są kluczowe dla Twojej strony, przeglądarka musi najpierw pobrać HTML, przeanalizować CSS, a dopiero później pobrać czcionki internetowe.
Dzięki atrybutowi link rel preload przeglądarka może zacząć pobierać te czcionki internetowe znacznie wcześniej, zaraz po przeanalizowaniu kodu HTML. W przypadku naszej aplikacji udało się w ten sposób skrócić o sekundę czas renderowania tekstu przy użyciu naszych czcionek internetowych.
Jeśli chcesz wstępnie wczytać czcionki za pomocą Google Fonts, nie jest to takie proste. Jest jeden haczyk.
Adresy URL czcionek Google, które podajemy w naszych arkuszach stylów, są regularnie aktualizowane przez zespół ds. czcionek. Te adresy URL mogą wygasnąć lub być regularnie aktualizowane, dlatego jeśli chcesz mieć pełną kontrolę nad wczytywaniem czcionek, zalecamy samodzielne hostowanie czcionek internetowych. To świetne rozwiązanie, ponieważ daje dostęp do takich funkcji jak link rel preload.
W naszym przypadku bardzo przydatne okazało się narzędzie Google Web Fonts Helper, które pomogło nam wyłączyć niektóre czcionki internetowe i skonfigurować je lokalnie. Warto je wypróbować.
Niezależnie od tego, czy używasz czcionek internetowych jako części kluczowych zasobów, czy jest to JavaScript, staraj się pomóc przeglądarce w jak najszybszym dostarczaniu kluczowych zasobów.
Funkcja eksperymentalna: wskazówki dotyczące priorytetów
Mamy dziś dla Ciebie coś specjalnego. Oprócz funkcji takich jak wskazówki dotyczące zasobów czy wstępne wczytywanie pracowaliśmy nad zupełnie nową eksperymentalną funkcją przeglądarki, którą nazywamy wskazówkami dotyczącymi priorytetu.
Jest to nowa funkcja, która umożliwia przekazywanie przeglądarce informacji o tym, jak ważny jest dany zasób. Udostępnia ona nowy atrybut – importance – o wartościach low, high lub auto.
Pozwala to przekazywać informacje o obniżaniu priorytetu mniej ważnych zasobów, takich jak niekrytyczne style, obrazy lub wywołania interfejsu Fetch API, aby zmniejszyć konkurencję. Możemy też zwiększyć priorytet ważniejszych elementów, takich jak obrazy główne.
W przypadku naszej aplikacji Oodle doprowadziło to do znalezienia praktycznego miejsca, w którym mogliśmy przeprowadzić optymalizację.
Zanim dodaliśmy do naszych obrazów leniwe wczytywanie, przeglądarka pobierała wszystkie obrazy z karuzeli z naszymi doodle na samym początku z wysokim priorytetem. Niestety najważniejsze dla użytkownika były obrazy znajdujące się pośrodku karuzeli. Ustawiliśmy więc bardzo niską ważność obrazów w tle, a bardzo wysoką ważność obrazów na pierwszym planie. Dzięki temu w przypadku wolnego połączenia 3G udało nam się skrócić czas pobierania i renderowania tych obrazów o 2 sekundy. To pozytywne doświadczenie.
Mamy nadzieję, że za kilka tygodni udostępnimy tę funkcję w Canary, więc wypatruj tej zmiany.
Opracuj strategię wczytywania czcionek internetowych
Typografia jest podstawą dobrego projektu, a jeśli używasz czcionek internetowych, najlepiej nie blokować renderowania tekstu i na pewno nie chcesz wyświetlać niewidocznego tekstu.
Podkreślamy to teraz w Lighthouse za pomocą audytu Unikaj niewidocznego tekstu podczas wczytywania czcionek internetowych.
Jeśli wczytujesz czcionki internetowe za pomocą bloku font-face, pozwalasz przeglądarce zdecydować, co zrobić, jeśli pobieranie czcionki internetowej trwa długo. Niektóre przeglądarki będą czekać na to nawet 3 sekundy, zanim przejdą na czcionkę systemową, a gdy czcionka zostanie pobrana, zastąpią ją.
Staramy się unikać niewidocznego tekstu, więc w tym przypadku nie moglibyśmy zobaczyć klasycznych doodle z tego tygodnia, gdyby czcionka internetowa ładowała się zbyt długo. Na szczęście dzięki nowej funkcji o nazwie
font-display masz 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 czcionki pomaga określić, jak czcionki internetowe będą renderowane lub jak będą zastępowane w zależności od czasu potrzebnego na ich zamianę.
W tym przypadku używamy zamiany wyświetlania czcionki. Wartość swap oznacza, że okres blokowania czcionki wynosi 0 sekund, a okres zamiany jest nieskończony. Oznacza to, że przeglądarka od razu narysuje tekst, używając czcionki zastępczej, jeśli wczytywanie czcionki zajmie trochę czasu. Gdy czcionka będzie dostępna, nastąpi zamiana.
W przypadku naszej aplikacji było to świetne rozwiązanie, ponieważ pozwoliło nam wyświetlić istotny tekst na bardzo wczesnym etapie i przejść na czcionkę internetową, gdy była gotowa.
Jeśli używasz czcionek internetowych, co robi duża część internetu, zastosuj dobrą strategię wczytywania czcionek internetowych.
Istnieje wiele funkcji platformy internetowej, których możesz użyć, aby zoptymalizować ładowanie czcionek. Warto też zapoznać się z repozytorium Zach Leatherman Web Font Recipes, ponieważ jest ono naprawdę przydatne.
Ograniczanie skryptów blokujących renderowanie
Są inne części naszej aplikacji, które możemy umieścić wcześniej w łańcuchu pobierania, aby zapewnić przynajmniej podstawową wygodę użytkownika.
Na pasku osi czasu Lighthouse widać, że w pierwszych sekundach, gdy wczytywane są wszystkie zasoby, użytkownik nie widzi żadnych treści.
Pobieranie i przetwarzanie zewnętrznych arkuszy stylów blokuje proces renderowania, uniemożliwiając mu postęp.
Możemy spróbować zoptymalizować ścieżkę krytycznego renderowania, dostarczając niektóre style nieco wcześniej.
Jeśli wyodrębnimy style odpowiedzialne za to początkowe renderowanie i wstawimy je w kodzie 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ć w stronę krytyczne treści w pliku index.html podczas etapu kompilacji.
Chociaż ten moduł wykonał za nas większość pracy, nadal było trochę trudno sprawić, aby działał płynnie na różnych trasach.
Jeśli nie zachowasz ostrożności lub struktura witryny jest bardzo złożona, wprowadzenie tego typu wzorca może być bardzo trudne, jeśli od początku nie zaplanujesz architektury powłoki aplikacji.
Dlatego tak ważne jest, aby od samego początku brać pod uwagę wydajność. Jeśli od początku nie będziesz projektować z myślą o wydajności, istnieje duże prawdopodobieństwo, że później napotkasz problemy.
Ostatecznie podjęte przez nas ryzyko się opłaciło. Udało nam się to zrobić i aplikacja zaczęła dostarczać treści znacznie wcześniej, co znacznie skróciło czas pierwszego znaczącego wyrenderowania.
Wynik
To długa lista optymalizacji wydajności, które zastosowaliśmy w naszej witrynie. Przyjrzyjmy się wynikowi. Tak wyglądało wczytywanie naszej aplikacji na urządzeniu mobilnym średniej klasy w sieci 3G przed optymalizacją i po niej.
Wynik wydajności Lighthouse wzrósł z 23 do 91. To całkiem niezłe postępy pod względem szybkości. Wszystkie zmiany zostały wprowadzone na podstawie ciągłego sprawdzania i stosowania się do raportu Lighthouse. Jeśli chcesz sprawdzić, jak technicznie wprowadziliśmy wszystkie ulepszenia, zajrzyj do naszego repozytorium, a zwłaszcza do PR-ów, które się w nim znalazły.
Skuteczność predykcyjna – wrażenia użytkownika oparte na danych
Uważamy, że systemy uczące się stwarzają wiele ciekawych możliwości w przyszłości w różnych dziedzinach. Jednym z pomysłów, który, mamy nadzieję, w przyszłości zachęci do dalszych eksperymentów, jest to, że prawdziwe dane 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 potrzebować, a co za tym idzie, co warto wstępnie pobrać, załadować lub zapisać w pamięci podręcznej. Jeśli trafimy, możemy priorytetowo potraktować niewielką ilość zasobów, ale trudno jest rozszerzyć to na całą witrynę.
Obecnie mamy dostępne dane, które pozwalają nam lepiej optymalizować kampanie. Korzystając z interfejsu API do raportowania Google Analytics, możemy sprawdzić następną najpopularniejszą stronę i odsetek wyjść dla dowolnego adresu URL w naszej witrynie, a tym samym wyciągnąć wnioski dotyczące tego, które zasoby powinniśmy traktować priorytetowo.
Jeśli połączymy to z dobrym modelem prawdopodobieństwa, unikniemy marnowania danych użytkownika przez agresywne wstępne pobieranie treści. Możemy wykorzystać te dane z Google Analytics i użyć uczenia maszynowego oraz modeli takich jak łańcuchy Markowa lub sieć neuronowa, aby wdrożyć takie modele.
Aby ułatwić przeprowadzanie takich eksperymentów, wprowadzamy nową inicjatywę o nazwie Guess.js.
Guess.js to projekt, który koncentruje się na wrażeniach użytkowników w internecie opartych na danych. Mamy nadzieję, że zachęci Cię to do wykorzystywania danych do poprawy wydajności witryny i nie tylko. Wszystko to jest dostępne na GitHubie jako oprogramowanie open source. Został on opracowany we współpracy ze społecznością open source przez Minko Gecheva, Kyle’a Matthewsa z Gatsby, Katie Hempenius i wiele innych osób.
Wypróbuj Guess.js i podziel się z nami swoją opinią.
Podsumowanie
Wyniki i dane pomagają zwiększyć szybkość działania internetu, ale są tylko środkiem do celu, a nie celem samym w sobie.
Każdy z nas doświadczył powolnego wczytywania stron w podróży, ale teraz mamy możliwość zapewnienia użytkownikom większej wygody dzięki bardzo szybkiemu wczytywaniu.
Poprawa wydajności to proces. Wiele małych 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 dostępne wrażenia.
Specjalne podziękowania dla: Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, Lighthouse i Google Doodles.