Dwa sposoby pobierania z wyprzedzeniem: tagi <link> oraz nagłówki HTTP

Demián Renzulli
Demián Renzulli

W tym ćwiczeniu z programowania zaimplementujesz wstępne pobieranie na 2 sposoby: za pomocą dyrektywy <link rel="prefetch"> i nagłówka HTTP Link.

Przykładowa aplikacja to witryna z promocyjną stroną docelową, na której znajduje się specjalny rabat na najlepiej sprzedającą się koszulkę w sklepie. Ponieważ strona docelowa zawiera link do jednego produktu, można założyć, że duży odsetek użytkowników przejdzie na stronę ze szczegółami produktu. Dzięki temu strona produktu jest dobrym kandydatem do wstępnego pobierania na stronie docelowej.

pomiar wyników;

Najpierw ustal wydajność bazową:

  1. Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
  2. Kliknij kartę Sieć.

  3. Z listy Ograniczanie przepustowości wybierz Szybkie 3G, aby symulować wolne połączenie.

  4. Aby wczytać stronę produktu, w przykładowej aplikacji kliknij Kup teraz.

Wczytywanie strony product-details.html trwa około 600 ms:

Panel sieci pokazujący czasy ładowania pliku product-details.html

Aby ułatwić nawigację, wstaw na stronie docelowej tag prefetch, aby wstępnie pobrać stronę product-details.html:

  • Dodaj ten element <link> na początku pliku views/index.html:
<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">

      <link rel="prefetch" href="/product-details.html" as="document">
      ...
</head>

Atrybut as jest opcjonalny, ale zalecany. Pomaga przeglądarce ustawić odpowiednie nagłówki i określić, czy zasób jest już w pamięci podręcznej. Przykładowe wartości tego atrybutu to: document, script, style, font, image i inne.

Aby sprawdzić, czy wstępne pobieranie działa:

  1. Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
  2. Kliknij kartę Sieć.

  3. Z listy Ograniczanie przepustowości wybierz Szybkie 3G, aby symulować wolne połączenie.

  4. Usuń zaznaczenie pola wyboru Wyłącz pamięć podręczną.

  5. Ponownie załaduj aplikację.

Teraz, gdy strona docelowa się wczytuje, wczytuje się też product-details.html, ale z najniższym priorytetem:

Panel Sieć pokazujący wstępnie pobrany plik product-details.html.

Strona jest przechowywana w pamięci podręcznej HTTP przez 5 minut, po czym obowiązują normalne reguły Cache-Control dotyczące dokumentu. W tym przypadku product-details.html ma nagłówek cache-control o wartości public, max-age=0, co oznacza, że strona jest przechowywana przez 5 minut.

Ponowna ocena skuteczności

  1. Ponownie załaduj aplikację.
  2. Aby wczytać stronę produktu, w przykładowej aplikacji kliknij Kup teraz.

Sprawdź panel Sieć. W porównaniu z pierwotnym śledzeniem sieci występują 2 różnice:

  • W kolumnie Rozmiar widnieje „pamięć podręczna pobierania z wyprzedzeniem”, co oznacza, że ten zasób został pobrany z pamięci podręcznej przeglądarki, a nie z sieci.
  • Kolumna Czas pokazuje, że czas wczytywania dokumentu wynosi teraz około 10 ms.

To o 98% mniej niż w przypadku poprzedniej wersji, która zajmowała około 600 ms.

Panel Sieć pokazujący plik product-details.html pobrany z pamięci podręcznej pobierania z wyprzedzeniem.

Dodatkowe punkty: użyj prefetch jako stopniowego udoskonalenia

Pobieranie z wyprzedzeniem najlepiej wdrożyć jako stopniowe ulepszenie dla użytkowników, którzy korzystają z internetu przy szybkim połączeniu. Za pomocą interfejsu Network Information API możesz sprawdzać warunki sieci i na ich podstawie dynamicznie wstawiać tagi wstępnego pobierania. Dzięki temu możesz zminimalizować zużycie danych i zaoszczędzić pieniądze użytkowników, którzy korzystają z wolnych lub drogich pakietów danych.

Aby wdrożyć adaptacyjne pobieranie wstępne, najpierw usuń tag <link rel="prefetch"> z elementu views/index.html:

<!doctype html>
  <html>
    <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
       <link rel="prefetch" href="/product-details.html" as="document">
       ...
    </head>

Następnie dodaj ten kod do pliku public/script.js, aby zadeklarować funkcję, która dynamicznie wstawia tag prefetch, gdy użytkownik korzysta z szybkiego połączenia:

function injectLinkPrefetchIn4g(url) {
    if (window.navigator.connection.effectiveType === '4g') {
        //generate link prefetch tag
        const linkTag = document.createElement('link');
        linkTag.rel = 'prefetch';
        linkTag.href = url;
        linkTag.as = 'document';

        //inject tag in the head of the document
        document.head.appendChild(linkTag);
    }
}

Funkcja działa w ten sposób:

  • Sprawdza właściwość effectiveTypeinterfejsie Network Information API, aby określić, czy użytkownik korzysta z połączenia 4G (lub szybszego).
  • Jeśli ten warunek jest spełniony, generuje tag <link> z atrybutem prefetch jako typem wskazówki, przekazuje adres URL, który zostanie wstępnie pobrany, w atrybucie href i wskazuje, że zasób jest plikiem HTML document w atrybucie as.
  • Na koniec dynamicznie umieszcza skrypt w sekcji head strony.

Następnie dodaj script.js do views/index.html, tuż przed tagiem zamykającym </body>:

<body>
      ...
      <script src="/script.js"></script>
</body>

Umieszczenie żądania script.js na końcu strony gwarantuje, że zostanie ono załadowane i wykonane po przeanalizowaniu i załadowaniu strony.

Aby mieć pewność, że wstępne pobieranie nie będzie kolidować z zasobami krytycznymi bieżącej strony, dodaj ten fragment kodu, aby wywołać funkcję injectLinkPrefetchIn4g() w zdarzeniu window.load:

<body>
      ...
      <script src="/script.js"></script>
      <script>
           window.addEventListener('load', () => {
                injectLinkPrefetchIn4g('/product-details.html');
           });
      </script>
</body>

Strona docelowa wstępnie pobiera teraz product-details.html tylko w przypadku szybkich połączeń. Aby to sprawdzić:

  1. Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
  2. Kliknij kartę Sieć.
  3. Z listy Ograniczanie wybierz Online.
  4. Ponownie załaduj aplikację.

W panelu Sieć powinna być widoczna ikona product-details.html:

Panel Sieć pokazujący wstępnie pobrany plik product-details.html.

Aby sprawdzić, czy strona produktu nie jest wstępnie pobierana przy wolnych połączeniach:

  1. Z listy Ograniczanie przepustowości wybierz Wolne 3G.
  2. Ponownie załaduj aplikację.

Panel Sieć powinien zawierać tylko zasoby strony docelowej bez product-details.html:

Panel sieciowy pokazujący, że plik product-details.html nie jest wstępnie pobierany.

Nagłówek HTTP Link może służyć do wstępnego pobierania tego samego typu zasobów co tag link. Decyzja o tym, kiedy użyć jednego lub drugiego typu, zależy głównie od Twoich preferencji, ponieważ różnica w skuteczności jest nieznaczna. W tym przypadku użyjesz go do wstępnego pobrania głównego arkusza CSS strony produktu, aby jeszcze bardziej poprawić jej renderowanie.

Dodaj nagłówek HTTP Link dla style-product.css w odpowiedzi serwera na stronie docelowej:

  1. Otwórz plik server.js i poszukaj w nim get() obsługi adresu URL głównego: /.
  2. Na początku funkcji obsługi dodaj ten wiersz:
app.get('/', function(request, response) {
    response.set('Link', '</style-product.css>; rel=prefetch');
    response.sendFile(__dirname + '/views/index.html');
});
  1. Aby otworzyć Narzędzia dla programistów, naciśnij Ctrl+Shift+J (lub Command+Option+J na Macu).
  2. Kliknij kartę Sieć.
  3. Ponownie załaduj aplikację.

Element style-product.css jest teraz wstępnie pobierany z najniższym priorytetem po załadowaniu strony docelowej:

Panel Sieć pokazujący wstępnie pobrany plik style-product.css.

Aby otworzyć stronę usługi, kliknij Kup teraz. Otwórz panel Sieć:

Panel Sieć pokazujący plik style-product.css pobrany z pamięci podręcznej pobierania z wyprzedzeniem.

Plik style-product.css został pobrany z „pamięci podręcznej wstępnego pobierania” i wczytanie go zajęło tylko 12 ms.