Łatwe wykonywanie zadań w internecie – Google I/O 2018

Na konferencji Google IO 2018 przedstawiliśmy podsumowanie narzędzi, bibliotek i technik optymalizacji, które ułatwiają zwiększanie wydajności stron internetowych. Poniżej opisujemy, jak działa aplikacja Oodles Theater, a także nasze eksperymenty z funkcją przewidywania wczytywania i nową inicjatywą Guess.js.

Addy Osmani
Addy Osmani
Ewa Gasperowicz

Przez ostatni rok pracowaliśmy nad wypracowaniem sposobów na przyspieszenie działania sieci. W ten sposób powstały nowe narzędzia, metody i biblioteki, którymi chętnie podzielimy się z Wami w tym artykule. W pierwszej części zaprezentujemy techniki optymalizacji, które stosujemy w praktyce podczas tworzenia aplikacji Oodles Theater. W drugiej części omówimy nasze eksperymenty z wczytywaniem predykcyjnym i nową inicjatywę Guess.js.

Konieczność zwiększenia wydajności

Z każdym rokiem internet staje się coraz silniejszy. W stanie internetu widać, że mediana strony na urządzeniach mobilnych ma około 1,5 MB, w większości przypadków JavaScript i obrazy.

rosnący rozmiar witryn wraz z innymi czynnikami, takimi jak czas oczekiwania w sieci, ograniczenia procesora, wzorce blokowania renderowania czy zbędny kod innych firm, przyczynia się do skomplikowanej łamigłówki dla wydajności.

Większość użytkowników ocenia szybkość jako na pierwszym miejscu w hierarchii UX. Nie ma w tym nic dziwnego, bo do chwili zakończenia ładowania strony nic nie da się zrobić. Nie da się wydobyć z treści strony żadnej wartości, nie sposób podziwiać jej estetyki.

Piramid hierarchii UX
Rys. 1. Jak ważna jest dla użytkowników szybkość? (Speed Matters, Vol. 3)

Wiemy, że wydajność ma znaczenie dla użytkowników, ale może też wydawać się tajemnicą, by dowiedzieć się, od czego zacząć optymalizację. Na szczęście istnieją narzędzia, które mogą Ci w tym pomóc.

Lighthouse – podstawa przepływu pracy

Lighthouse to część Narzędzi deweloperskich w Chrome, która umożliwia przeprowadzenie audytu witryny i daje wskazówki, jak ją ulepszyć.

Niedawno wprowadziliśmy kilka nowych audytów wydajności, które są bardzo przydatne w codziennych zadaniach programistycznych.

Nowe audyty Lighthouse
Rys. 2. Nowe audyty Lighthouse

Zobaczmy, jak można je wykorzystać na praktycznym przykładzie: aplikacja Oodles Theater. To mała wersja demonstracyjna aplikacji internetowej, w której możesz wypróbować nasze ulubione interaktywne doodle Google, a nawet zagrać w coś lub kilka.

Podczas tworzenia aplikacji chcieliśmy mieć pewność, że będzie ona maksymalnie wydajna. Punktem początkowym optymalizacji był raport Lighthouse.

Raport Lighthouse dotyczący aplikacji Oodles
Rys. 3. Raport Lighthouse dotyczący aplikacji Oodles

Początkowe wyniki naszej aplikacji widoczne w raporcie Lighthouse były okropne. W sieci 3G użytkownik musiał poczekać 15 sekund na pierwsze wyrenderowanie reklamy lub na pokazanie aplikacji w sposób interaktywny. Narzędzie Lighthouse zwróciło uwagę na wiele problemów z naszą witryną, a ogólny wynik wydajności 23 odzwierciedla to dokładnie.

Strona ważyła około 3,4 MB i chceliśmy zrzucić trochę tłuszczu.

Rozpoczęło się nasze pierwsze wyzwanie dotyczące wydajności: znajdź elementy, które łatwo usunąć, nie wpływając na ogólne wrażenia.

Możliwości optymalizacji skuteczności

Usuń niepotrzebne zasoby

Jest kilka oczywistych rzeczy, które można bezpiecznie usunąć: odstępy i komentarze.

Zysk z minifikacji
Rys. 4. Zmniejsz i skompresuj JavaScript oraz CSS

Lighthouse podkreśla tę możliwość w audycie CSS i JavaScript. W procesie kompilacji korzystaliśmy z pakietu webpack. Aby uzyskać minifikację, użyliśmy wtyczki Uglify JS.

Minimalizacja to częste zadanie, dlatego powinno być możliwe znalezienie gotowego rozwiązania dla dowolnego procesu kompilacji, z którego użyjesz.

Inną przydatną opcją kontroli w tym obszarze jest Włącz kompresję tekstu. Nie ma powodu, aby wysyłać nieskompresowane pliki, a większość sieci CDN obsługuje obecnie tę funkcję od razu.

Do hostowania kodu korzystaliśmy z Hostingu Firebase, a Firebase domyślnie umożliwia korzystanie z gziping. Dzięki temu, że kod został umieszczony w rozsądnej sieci CDN, usługa ta jest dostępna bezpłatnie.

Choć gzip jest bardzo popularnym sposobem kompresowania, inne mechanizmy, takie jak Zopfli i Brotli, również ją utrudniają. Większość przeglądarek obsługuje Brotli. Do wstępnego skompresowania zasobów przed wysłaniem ich na serwer możesz używać plików binarnych.

Używaj zasad wydajnej pamięci podręcznej

Zadbaliśmy o to, aby nie wysyłać zasobów dwukrotnie, jeśli są one niepotrzebne.

Audyt dotyczący nieefektywnych zasad pamięci podręcznej w Lighthouse pokazał nam, że możemy optymalizować nasze strategie buforowania, aby dokładnie to osiągnąć. Ustawiając na serwerze nagłówek „max-age data ważności”, mamy pewność, że przy kolejnych wizytach użytkownik może ponownie wykorzystać pobrane wcześniej zasoby.

Najlepiej jest przechowywać jak najwięcej zasobów w pamięci podręcznej przez najdłuższy możliwy okres i udostępniać tokeny weryfikacyjne, aby sprawnie przeprowadzić ponowną weryfikację zaktualizowanych zasobów.

Usuń nieużywany kod

Do tej pory usunęliśmy oczywiste części niepotrzebnego pobierania, ale co z mniej oczywistymi elementami? Może to być na przykład nieużywany kod.

Zasięg kodu w Narzędziach deweloperskich
Rys. 5. Sprawdź zasięg kodu

Czasami umieszczamy w naszej aplikacji kod, który nie jest naprawdę potrzebny. Zdarza się to zwłaszcza wtedy, gdy pracujesz nad aplikacją przez dłuższy czas, Twój zespół lub Twoje zależności się zmieniają, a czasem zostaje w tle biblioteka osierocona. Dokładnie tak nam się przydarzyło.

Początkowo korzystaliśmy z biblioteki Material Komponenty do szybkiego tworzenia prototypu aplikacji. Z czasem zmieniliśmy wygląd i styl, więc zupełnie zapomnieliśmy o tej bibliotece. Na szczęście sprawdzenie zasięgu kodu pomogło nam znaleźć go na nowo w naszym pakiecie.

Statystyki pokrycia kodu możesz sprawdzać w Narzędziach deweloperskich zarówno w przypadku środowiska wykonawczego, jak i czasu wczytywania aplikacji. Możesz zobaczyć dwa duże czerwone paski na dolnym zrzucie ekranu – mieliśmy ponad 95% nieużywanego kodu CSS i sporo kodu JavaScript.

Narzędzie Lighthouse również wykryło ten problem podczas kontroli nieużywanych reguł CSS. Okazało się, że można było zaoszczędzić ponad 400 KB. Wróćmy więc do kodu i usunęliśmy z tej biblioteki zarówno część JavaScriptu, jak i CSS.

Po usunięciu adaptera MVC nasze style spadną do 10 KB
Rys. 6. Po usunięciu adaptera MVC nasze style spadną do 10 KB.

W rezultacie nasz pakiet CSS skrócił się 20 razy, co jest dobre przy drobnym, dwuwierszowym zatwierdzeniu.

Oczywiście zwiększyło to nasz wynik skuteczności, a także znacznie poprawił się czas do pełnej interaktywności.

Jednak przy takich zmianach nie wystarczy samo sprawdzanie danych i wyników. Usunięcie rzeczywistego kodu nigdy nie wiąże się z ryzykiem, dlatego zawsze należy zwracać uwagę na potencjalne regresje.

Nasz kod nie został wykorzystany w 95% – gdzieś nadal jest to 5%. Najwyraźniej jeden z komponentów wciąż używał stylów z tej biblioteki – małych strzałek na suwaku doodli. Ponieważ był on mały, mogliśmy po prostu ręcznie włączyć ten styl z powrotem do przycisków.

Przyciski są uszkodzone z powodu brakującej biblioteki
Rys. 7. Jeden z komponentów wciąż korzystał z usuniętej biblioteki

Jeśli więc usuwasz kod, musisz zadbać o odpowiedni przepływ pracy związany z testowaniem, który pomoże uniknąć potencjalnych regresji wizualnych.

Unikaj bardzo dużych ładunków sieciowych

Wiemy, że duże zasoby mogą spowalniać wczytywanie stron internetowych. Mogą generować koszty dla naszych użytkowników i mogą mieć ogromny wpływ na ich abonamenty, dlatego trzeba o tym pamiętać.

Usługa Lighthouse wykryła problem z niektórymi ładunkami sieciowymi za pomocą kontroli ładunku sieciowego Enormous.

Wykrywanie dużych ładunków sieciowych
Rys. 8. Wykrywaj ogromne ładunki sieciowe

Zauważyliśmy, że mieliśmy ponad 3 MB kodu, który był wysyłany, a to sporo, zwłaszcza na komórce.

Na samej górze listy widać, że mamy pakiet dostawców języka JavaScript o rozmiarze 2 MB nieskompresowanego kodu. Ten problem jest również wyróżniony przez pakiet webpack.

Jak można się domyślić, najszybsza prośba to ta, która nie została wysłana.

Mierz wartość każdego komponentu, który wyświetlasz użytkownikom, mierz ich skuteczność i rozmawiaj z Tobą o tym, czy warto je sprzedać. Ponieważ czasami zasoby te mogą być odroczone, leniwie ładowane lub przetwarzane w czasie bezczynności.

W naszym przypadku mamy do czynienia z wieloma pakietami JavaScript, więc mieliśmy szczęście, bo społeczność JavaScript ma bogaty zestaw narzędzi do kontroli takich pakietów.

Kontrola pakietów JavaScript
Rys. 9. Kontrola pakietów JavaScript

Zaczęliśmy od analizatora pakietów SDK, który informował nas, że w naszym systemie jest zależność o nazwie unicode, której rozmiar to 1,6 MB analizowanego kodu JavaScriptu.To sporo.

Następnie przeszliśmy do edytora i za pomocą wtyczki do obsługi kosztów importu kodu wizualnego zobrazowaliśmy koszt każdego importowanego modułu. Dzięki temu udało nam się ustalić, który komponent zawierał kod odwołujący się do tego modułu.

Potem przeszliśmy na inne narzędzie – BundlePhobia. Jest to narzędzie, które pozwala wpisać nazwę pakietu NPM i zobaczyć, jaki jest szacowany rozmiar jego zminimalizowanego i skompresowanego pliku gzip. Znaleźliśmy świetną alternatywę dla naszego modułu pamięci ważącego zaledwie 2,2 KB, więc ją zmodyfikowaliśmy.

Miało to duży wpływ na nasze wyniki. Między tą zmianą i odkryciem innych możliwości zmniejszenia rozmiaru pakietu JavaScript zaoszczędziliśmy 2, 1 MB kodu.

Po uwzględnieniu rozmiaru skompresowanego i zmniejszonego pakietu odnotowaliśmy ogólny wzrost o 65%. Okazało się, że naprawdę warto to zrobić.

Staraj się więc unikać pobierania z Twoich witryn i aplikacji niepotrzebnych plików. Sporządź wykaz swoich zasobów i oceń ich wpływ na skuteczność, ponieważ może to mieć duży wpływ na ich skuteczność, dlatego pamiętaj o regularnym ich sprawdzaniu.

Krótszy czas uruchamiania JavaScript dzięki podziałowi kodu

Duże ładunki sieciowe mogą mieć duży wpływ na naszą aplikację, ale jest coś, co może mieć naprawdę duży wpływ – JavaScript.

JavaScript to najdroższy zasób. Jeśli w przypadku urządzeń mobilnych wysyłasz duże pakiety kodu JavaScript, może to opóźnić czas, po którym użytkownicy będą mogli wejść w interakcję z komponentami interfejsu. Oznacza to, że mogą klikać interfejs, ale nic ważnego nie dzieje. Dlatego chcemy wiedzieć, dlaczego JavaScript jest tak kosztowny.

Tak właśnie przeglądarka przetwarza JavaScript.

Przetwarzanie JavaScriptu
Rys. 10. Przetwarzanie JavaScriptu

Najpierw musimy pobrać ten skrypt. Mamy mechanizm JavaScript, który następnie musi go przeanalizować, skompilować i wykonać.

Te fazy są czymś, co nie zajmuje dużo czasu na zaawansowanym urządzeniu, takim jak komputer stacjonarny, laptop, czy nawet na zaawansowanym telefonie. Jednak na przeciętnym telefonie komórkowym ten proces może potrwać 5–10 razy dłużej. To spowalnia interaktywność, więc spróbujmy ograniczyć tę kwestię.

Aby ułatwić wykrywanie takich problemów w aplikacji, wprowadziliśmy w Lighthouse nową kontrolę czasu uruchamiania JavaScriptu.

Czas uruchamiania JavaScriptu
Rys. 11. Kontrola czasu uruchamiania JavaScriptu

W przypadku aplikacji Oodle informowała nas, że rozruch JavaScriptu trwał 1,8 sekundy. W tym przypadku statycznie importowaliśmy wszystkie nasze trasy i komponenty do jednego monolitycznego pakietu JavaScript.

Jedną z metod, które pozwalają obejść ten problem, jest podział kodu.

Dzielenie kodu jest jak pizza

Dzielenie kodu to metoda polegająca na tym, że zamiast dawać użytkownikom JavaScript w całości, co by dać im tylko jeden kawałek naraz?

Podział kodu można zastosować na poziomie trasy lub komponentu. Świetnie działa z bibliotekami React i React Loadable, Vue.js, Angular, Polymer, Preact i wieloma innymi.

Włączyliśmy w naszej aplikacji podział kodu i przełączyliśmy się z importu statycznego na dynamiczny, co umożliwiło asynchroniczne, leniwe ładowanie kodu w miarę potrzeb.

Podział kodu z dynamicznym importem
Rys. 13. Podział kodu za pomocą importu dynamicznego

Wpłynęło to na zmniejszenie rozmiaru pakietów, a jednocześnie skrócenie czasu uruchamiania JavaScriptu. Zajęło to 0,78 sekundy, a aplikacja działa o 56% szybciej.

Jeśli tworzysz środowisko oparte na języku JavaScript, wysyłaj kod tylko do użytkownika, który jest w stanie potrzebny.

Skorzystaj z takich zagadnień jak dzielenie kodu, poznaj np. drżenie drzew oraz przejrzyj repozytorium webpack-libs-Optimizations, gdzie znajdziesz kilka pomysłów na zmniejszenie rozmiaru biblioteki w przypadku korzystania z pakietu Webpack.

Zoptymalizuj obrazy

Dowcip o wydajności wczytywania obrazu

W aplikacji Oodle jest dużo obrazów. Niestety Latarnia Lighthouse podchodziła do tego znacznie mniej entuzjastycznie. W rzeczywistości nie udało nam się spełnić wszystkich 3 kontroli obrazów.

Zapomnieliśmy zoptymalizować obrazy, źle dopasowywały się do nich rozmiar. Mogliśmy też trochę odzyskać dzięki zastosowaniu innych formatów obrazów.

Audyty obrazów
Rys. 14. Audyty obrazów w Lighthouse

Zaczęliśmy od optymalizacji obrazów.

Do jednorazowej optymalizacji możesz użyć narzędzi wizualnych, takich jak ImageOptim lub XNConvert.

Bardziej zautomatyzowany sposób polega na dodaniu do procesu kompilacji etapu optymalizacji obrazów przy użyciu bibliotek takich jak imagemin.

Dzięki temu będziesz mieć pewność, że obrazy dodawane w przyszłości będą automatycznie optymalizowane. Niektóre sieci CDN (np. Akamai) i rozwiązania innych firm, takie jak Cloudinary, Fastly czy Uploadcare, oferują kompleksowe rozwiązania w zakresie optymalizacji obrazów, dzięki którym możesz po prostu przechowywać obrazy w tych usługach.

Jeśli nie chcesz tego robić ze względu na koszty lub opóźnienia, możesz skorzystać z projektów takich jak Thumbor czy Imageflow.

Optymalizacja przed i po
Rys. 15. Optymalizacja przed i po

Nasz plik PNG z tła został oznaczony w pakiecie internetowym jako duży – i tak. Po prawidłowym dostosowaniu rozmiaru do widocznego obszaru i zastosowaniu go przez ImageOptim spadliśmy do 100 kB, co jest akceptowalne.

Powtarzanie tych czynności przy wielu obrazach w witrynie pozwoliło nam znacznie obniżyć ogólną wagę strony.

Używanie odpowiedniego formatu treści animowanych

GIF-y mogą być naprawdę drogie. Co ciekawe, format GIF nigdy nie był przeznaczony jako platforma animacji. Dlatego przełączenie się na bardziej odpowiedni format wideo zapewnia duże oszczędności w zakresie rozmiaru plików.

W aplikacji Oodle zastosowaliśmy GIF-a jako sekwencję wprowadzenia na stronie głównej. Według narzędzia Lighthouse moglibyśmy zaoszczędzić ponad 7 MB, przechodząc na bardziej wydajny format wideo. Nasz klip ważył około 7,3 MB, czyli za dużo, jak na jakąś rozsądną stronę.Zamiast tego utworzyliśmy z niego element wideo z 2 plikami źródłowymi: MP4 i WebM, który zapewnia obsługę szerszej przeglądarki.

Zastąp animowane GIF-y filmem
Rys. 16. Zastąp animowane GIF-y filmem

Za pomocą narzędzia FFmpeg skonwertowaliśmy GIF-a z animacją do pliku MP4. Format WebM zapewnia jeszcze większe oszczędności – interfejs ImageOptim API może wykonać 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ę zaoszczędzić ponad 80% naszej wagi. Zmniejszyliśmy ilość miejsca do 1 MB.

Jednak 1 MB to duży zasób, który można wykorzystać, zwłaszcza w przypadku użytkownika z ograniczoną przepustowością. Na szczęście mogliśmy użyć interfejsu Effective Type API, który pozwoliłby nam stwierdzić, że pliki mają wolne łącze, i zamiast tego mają znacznie mniejszy plik JPEG.

Ten interfejs wykorzystuje efektywny czas błądzenia i wartości wyłączenia do oszacowania typu sieci, z którego korzysta użytkownik. Zwraca tylko ciąg znaków, wolne połączenie 2G, 2G, 3G lub 4G. W zależności od tej wartości możemy więc zastąpić element wideo obrazem, jeśli użytkownik korzysta z łącza poniżej 4G.

if (navigator.connection.effectiveType) { ... }

To trochę zniekształca działanie, ale przynajmniej strona działa przy powolnym połączeniu.

Leniwe ładowanie obrazów poza ekranem

Obrazy są często wczytywane przy użyciu karuzeli, suwaków lub bardzo długich stron, nawet jeśli użytkownik nie widzi ich od razu.

Lighthouse oznaczy to zachowanie podczas kontroli obrazów poza ekranem. Możesz też samodzielnie sprawdzić ten efekt w panelu sieci w Narzędziach deweloperskich. Jeśli widzisz dużo obrazów przychodzących, a tylko kilka wyświetla się na stronie, być może warto skorzystać z leniwego ładowania.

Leniwe ładowanie nie jest jeszcze natywnie obsługiwane w przeglądarce. Aby dodać tę funkcję, musimy użyć JavaScriptu. Użyliśmy biblioteki leniwego rozmiaru, aby dodać działanie leniwego ładowania do coverów Oodle.

<!-- 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"/>

Leniwe rozmiary są przydatne, ponieważ nie tylko śledzi zmiany widoczności elementu, ale także aktywnie pobierają z wyprzedzeniem elementy, które znajdują się w pobliżu widoku, aby zapewnić użytkownikom optymalne wrażenia. Udostępnia też opcjonalną integrację narzędzia IntersectionObserver, co umożliwia bardzo skuteczne wyszukiwanie widoczności.

Po tej zmianie nasze obrazy będą pobierane na żądanie. Jeśli chcesz dowiedzieć się więcej, zajrzyj do images.guide – bardzo przydatnego i kompleksowego źródła informacji.

Pomóż przeglądarce szybko dostarczać krytyczne zasoby

Nie każdy bajt przesłany do przeglądarki jest równie ważny – przeglądarka o tym wie. Wiele przeglądarek korzysta z algorytmów heurystycznych, które określają, co należy pobrać w pierwszej kolejności. Z tego względu czasami pobierają kod CSS przed obrazami lub skryptami.

Dzięki temu jako autorzy stron możemy poinformować przeglądarkę, co jest dla nas naprawdę ważne. Na szczęście od kilku lat dostawcy przeglądarek dodają kilka funkcji, które mogą nam w tym pomóc, np. wskazówki dotyczące zasobów, takie jak link rel=preconnect, preload czy prefetch.

Te funkcje, które zostały udostępnione na platformie internetowej, pomagają przeglądarce pobrać właściwe informacje we właściwym czasie i mogą być nieco bardziej efektywne niż niektóre niestandardowe wczytywanie, oparte na logice wykonywane za pomocą skryptu.

Zobaczmy, jak Lighthouse faktycznie pomaga nam skutecznie korzystać z niektórych z tych funkcji.

W Lighthouse radzimy unikać wielu kosztownych podróży w obie strony do dowolnego źródła.

Unikaj wielokrotnych, kosztownych podróży w obie strony do dowolnego miejsca wylotu
Rys. 17. Unikaj wielokrotnych, kosztownych podróży w obie strony do dowolnego miejsca wylotu

W przypadku aplikacji Oodle intensywnie używamy czcionek Google Fonts. Za każdym razem, gdy umieścisz na stronie arkusz stylów Google Fonts, będzie on łączył maksymalnie dwie subdomeny. Z kolei Lighthouse wie, że jeśli uda się nam przyspieszyć połączenie, mogłoby zaoszczędzić nawet 300 milisekund.

Korzystając z funkcji link rel wstępna, możemy skutecznie zamaskować czas oczekiwania na połączenie.

Może to mieć naprawdę duży wpływ zwłaszcza na Google Fonts, gdzie na googleapis.com hostowane są pliki CSS dotyczące czcionek, a nasze zasoby czcionek – Gstatic. Zastosowaliśmy więc tę optymalizację i zaoszczędziliśmy o kilkaset milisekund.

Kolejną rzeczą, jaką sugeruje narzędzie Lighthouse, jest wstępne wczytywanie kluczowych żądań.

Wstępnie wczytuj żądania kluczy
Rys. 18. Wstępnie wczytaj żądania kluczy

Technologia <link rel=preload> jest naprawdę mocna, informuje przeglądarkę, że dany zasób jest potrzebny w ramach bieżącej nawigacji, i próbuje jak najszybciej pobrać ten zasób przez przeglądarkę.

Lighthouse mówi nam, że powinniśmy wstępnie załadować najważniejsze zasoby z czcionkami internetowymi, bo wczytujemy je w 2 czcionkach.

Wstępne wczytywanie czcionki internetowej wygląda tak: podając rel=preload, przekazujesz w polu as typ czcionki, a potem określasz typ czcionki, którą próbujesz wczytać, np. woff2.

Wpływ takiego działania na Twoją stronę jest niewielki.

Wpływ wstępnego wczytywania zasobów
Rys. 19. Wpływ wstępnego wczytywania zasobów

Zwykle bez stosowania wstępnego wczytywania linków relacyjnych, jeśli czcionki internetowe mają kluczowe znaczenie dla strony, przeglądarka musi najpierw pobrać kod HTML, przeanalizować kod CSS, a potem znacznie później pobrać czcionki internetowe.

Dzięki wstępnemu wczytywaniu link rel w kodzie HTML przeglądarka może rozpocząć pobieranie tych czcionek znacznie wcześniej. W przypadku naszej aplikacji udało się skrócić czas potrzebny na renderowanie tekstu przy użyciu czcionek internetowych.

Teraz nie jest to takie proste przy wstępnym wczytywaniu czcionek za pomocą Google Fonts.

Adresy URL czcionek Google określone w postaci krojów czcionek w arkuszach stylów są często aktualizowane przez zespół ds. czcionek. Mogą one wygasać lub być regularnie aktualizowane. Jeśli więc zależy Ci na pełnej kontroli nad wczytywaniem czcionek, zalecamy samodzielne hostowanie czcionek internetowych. To bardzo przydatne, bo daje dostęp do takich elementów, jak link rel wstępnie wczytywane.

W naszym przypadku okazało się, że narzędzie Google Web Fonts Helper bardzo przydaje się w trybie offline i umożliwia konfigurowanie niektórych czcionek internetowych lokalnie – warto z niego skorzystać.

Niezależnie od tego, czy używasz czcionek internetowych jako części najważniejszych zasobów, czy jest to JavaScript, postaraj się pomóc przeglądarce jak najszybciej dostarczyć te zasoby.

Funkcja eksperymentalna: wskazówki priorytetowe

mamy dziś coś dla Ciebie. Oprócz takich funkcji jak wskazówki dotyczące zasobów oraz wstępne wczytywanie pracujemy nad zupełnie nową, eksperymentalną funkcją przeglądarki, którą nazywamy priorytetowymi wskazówkami.

Ustaw priorytet treści, która jest widoczna na początku
Rys. 20. Wskazówki dotyczące priorytetu

Jest to nowa funkcja, która pozwala poinformować przeglądarkę o tym, jak ważny jest zasób. Dodaje nowy atrybut – ważność – o wartościach niskich, wysokich lub automatycznych.

Dzięki temu możemy obniżyć priorytet mniej ważnych zasobów, np. niekrytycznych stylów, obrazów lub wywołań interfejsu API, aby ograniczyć rywalizację. Możemy też podnosić priorytety ważniejszych rzeczy, takich jak banery powitalne.

W przypadku aplikacji Oodle dało to 1 praktyczne miejsce, w którym mogliśmy przeprowadzić optymalizację.

Ustaw priorytet treści, która jest widoczna na początku
Rys. 21. Ustaw priorytet treści, która jest widoczna na początku

Zanim dodaliśmy leniwe ładowanie obrazów, czyli działanie przeglądarki, mieliśmy taką karuzelę ze wszystkimi doodlami, a przeglądarka na samym początku karuzeli pobierała wszystkie obrazy z wysokim priorytetem. Niestety to właśnie obrazy na środku karuzeli były najważniejsze dla użytkownika. Dlatego ustawiliśmy znaczenie obrazów w tle na bardzo niskie, obrazy na pierwszym planie na bardzo wysokie. Mieliśmy 2-sekundowy wpływ na powolne połączenie 3G oraz szybkość pobierania i renderowania obrazów. Miło, miło, miło.

Mamy nadzieję wprowadzić tę funkcję w Canary w ciągu kilku tygodni, więc trzymaj rękę na pulsie.

Stosuj strategię wczytywania czcionek internetowych

Typografia ma kluczowe znaczenie dla prawidłowego projektu. Jeśli używasz czcionek internetowych, na pewno nie chcesz blokować renderowania tekstu ani wyświetlać niewidocznego tekstu.

Teraz wyróżniamy tę kwestię w narzędziu Lighthouse, a unikanie niewidocznego tekstu podczas wczytywania czcionek internetowych.

Unikaj niewidocznego tekstu podczas ładowania czcionek internetowych
Rys. 22. Unikaj niewidocznego tekstu podczas ładowania czcionek internetowych

Jeśli wczytujesz czcionki internetowe za pomocą bloku kroju czcionki, pozwalasz przeglądarce zdecydować, co zrobić, jeśli jej pobranie za długo trwa. Niektóre przeglądarki odczekują na to maksymalnie 3 sekundy, zanim przełączą się na czcionkę systemową. Później zastąpią ją czcionkę po pobraniu.

Staramy się unikać tego niewidocznego tekstu, więc w tym przypadku nie moglibyśmy zobaczyć klasycznych doodli z tego tygodnia, gdyby czcionka internetowa zajęłaby zbyt dużo czasu. Na szczęście nowa funkcja o nazwie font-display zapewnia Ci 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 pomaga określić, jak będą renderowane czcionki internetowe lub stosować je w zastępstwie na podstawie czasu potrzebnego na ich zamianę.

W tym przypadku używamy zamiany wyświetlania czcionki. Zamiana powoduje, że krój czcionki ma 0-sekundowy okres bloku i nieskończony okres zamiany. Oznacza to, że jeśli czcionka będzie się ładować dłużej, przeglądarka od razu zacznie ją wyświetlać przy użyciu czcionki zastępczej. Zostanie ona zastąpiona, gdy dostępna będzie krój czcionki.

W przypadku naszej aplikacji świetne jest to, że pozwoliło nam to na samym początku wyświetlić sensowny tekst i przejść na czcionkę internetową, gdy będzie gotowa.

Wynik wyświetlania czcionki
Rys. 23. Wynik wyświetlania czcionki

Jeśli używasz czcionek internetowych, pamiętaj, że w przypadku dużej części internetu warto zastosować skuteczną strategię ładowania czcionek internetowych.

Istnieje wiele funkcji platformy internetowej, które pomogą Ci zoptymalizować wczytywanie czcionek. Warto też zapoznać się z repozytorium Web Font Recipes Zacha Leathermana, które jest naprawdę świetne.

Zmniejsz liczbę skryptów blokujących renderowanie

Istnieją inne części naszej aplikacji, które moglibyśmy opublikować na wcześniejszym etapie łańcucha pobierania, aby nieco wcześniej zapewnić użytkownikom przynajmniej część podstawowych funkcji.

Na pasku osi czasu Lighthouse można zobaczyć, że w ciągu pierwszych kilku sekund, gdy wszystkie zasoby się wczytują, użytkownik nie widzi żadnych treści.

Ograniczenie możliwości korzystania z arkuszy stylów blokujących renderowanie
Rys. 24. Ograniczenie możliwości korzystania z arkuszy stylów blokujących renderowanie

Pobieranie i przetwarzanie zewnętrznych arkuszy stylów uniemożliwia proces renderowania.

Możemy spróbować zoptymalizować naszą krytyczną ścieżkę renderowania, pokazując niektóre style nieco wcześniej.

Po wyodrębnieniu stylów odpowiedzialnych za ten początkowy wyrenderowanie i umieszczeniu ich w kodzie HTML przeglądarka będzie mogła od razu wyrenderować je bez oczekiwania na dostarczenie zewnętrznych arkuszy stylów.

W naszym przypadku użyliśmy modułu NPM o nazwie Krytyczne, by w trakcie kroku kompilacji wbudować w stronę index.html najważniejsze treści.

Ten moduł wykonał za nas większość ciężkiej pracy, ale płynne działanie na różnych trasach było trochę trudne.

Jeśli nie zachowasz ostrożności lub struktura Twojej witryny jest bardzo złożona, może być Ci trudno wprowadzić ten wzorzec, jeśli nie planujesz od początku utworzenia architektury powłoki aplikacji.

Dlatego tak ważne jest wczesne uwzględnianie wydajności. Jeśli nie będziesz projektować pod kątem skuteczności od samego początku, istnieje duże prawdopodobieństwo, że później wystąpią problemy.

W ostatecznym rozrachunku ryzyko się opłaciło, ale aplikacja zaczęła wyświetlać treści znacznie wcześniej, co znacznie skróciło nasz pierwszy znaczący czas renderowania.

Wynik

To długa lista optymalizacji skuteczności, którą zastosowaliśmy w naszej witrynie. Przyjrzyjmy się efektom. Tak nasza aplikacja wczytuje się na średnim urządzeniu mobilnym w sieci 3G – przed optymalizacją i po niej.

Skuteczność narzędzia Lighthouse wzrosła z 23 do 91. To całkiem niezły postęp, jeśli chodzi o szybkość. Wszystkie zmiany były efektem naszych ciągłego sprawdzania i stosowania się do raportu Lighthouse. Jeśli chcesz sprawdzić, jak technicznie wdrożyliśmy wszystkie poprawki, zajrzyj do naszego repozytorium, a szczególnie tam znajdziesz dział PR.

Przewidywana skuteczność – wrażenia użytkowników oparte na danych

Uważamy, że systemy uczące się stwarzają niesamowitą szansę na przyszłość w wielu obszarach. Mamy nadzieję, że w przyszłości będziemy brać pod uwagę więcej eksperymentów – prawdziwe dane mogą wpływać na wrażenia użytkowników, które tworzymy.

Obecnie podejmujemy wiele arbitralnych decyzji dotyczących tego, czego użytkownik chce i czego potrzebuje. Dlatego podejmujemy decyzję o tym, co warto pobrać z wyprzedzeniem, wstępnie wczytywanym lub umieszczonym w pamięci podręcznej. Jeśli się mylimy, możemy priorytetowo traktować niewielką ilość zasobów, ale naprawdę trudno jest przeskalować ją na całą witrynę.

Dysponujemy danymi, które pomogą nam w podejmowaniu dziś optymalizacji. Korzystając z interfejsu API do raportowania Google Analytics, możemy przyjrzeć się bliżej następnej stronie i odsetkom porzuceń dla dowolnego adresu URL w naszej witrynie, aby wyciągnąć wnioski, które zasoby powinny postawić w pierwszej kolejności.

W połączeniu z modelem dobrego prawdopodobieństwa unikamy marnowania danych użytkowników przez zbyt agresywne pobieranie treści z wyprzedzeniem. Możemy wykorzystać te dane Google Analytics i wdrożyć takie modele za pomocą systemów uczących się oraz modeli, takich jak łańcuchy Markowa lub sieć neuronowa.

Grupowanie oparte na danych dla aplikacji internetowych
Rys. 25. Grupowanie oparte na danych dla aplikacji internetowych

Aby ułatwić przeprowadzanie tych eksperymentów, z przyjemnością informujemy o nowej inicjatywie, którą nazywamy Guess.js.

Guess.js
Rys. 26. Guess.js

Guess.js to projekt skoncentrowany na wrażeniach użytkowników witryn w oparciu o dane. Mamy nadzieję, że zainspiruje to do badań nad wykorzystaniem danych do zwiększania skuteczności stron internetowych. Wszystkie materiały na licencji open source są już dostępne na GitHubie. Powstał we współpracy ze społecznością open source Minko Gechev, Kyle Matthews z Gatsby, Katie Hempenius i wielu innych osób.

Wypróbuj Guess.js i podziel się z nami swoją opinią.

Podsumowanie

Wyniki i dane mogą pomóc w zwiększaniu szybkości działania internetu, ale są tylko środkami, a nie celami.

Zdarzało się kiedyś, że strony wczytują się powoli, ale teraz chcemy zapewnić użytkownikom jeszcze lepsze wrażenia i szybkie wczytywanie.

Poprawa skuteczności to podróż. Duże korzyści mogą przynieść wiele małych zmian. Korzystając z odpowiednich narzędzi do optymalizacji i obserwując raporty Lighthouse, możesz zapewnić użytkownikom lepsze wrażenia i zwiększyć ich integrację społeczną.

Specjalne podziękowania: Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Tom Ankers, latarnia morska i doodle Google.