Co dzieje się podczas nawigacji
To jest część 2 z 4-częściowej serii na blogu o tym, jak działa Chrome. W poprzednim poście omówiliśmy, jak różne procesy i wątki obsługują różne części przeglądarki. W tym poście szczegółowo omawiamy komunikację między procesami i wątkami, aby umożliwić wyświetlanie strony internetowej.
Przyjrzyjmy się prostemu przypadkowi przeglądania internetu: wpisujesz adres URL w przeglądarce, a potem przeglądarka pobiera dane z internetu i wyświetla stronę. W tym poście skupimy się na etapie, na którym użytkownik wysyła żądanie udostępnienia witryny, a przeglądarka przygotowuje się do jej wyrenderowania. Jest to tzw. nawigacja.
Zaczyna się od procesu przeglądarki
Jak omówiliśmy w części 1. Procesor, GPU, pamięć i architektura wieloprocesowa, wszystko poza kartą jest obsługiwane przez proces przeglądarki. W procesie przeglądarki są takie wątki jak wątek UI, który rysuje przyciski i pola do wprowadzania danych w przeglądarce, wątek sieciowy, który zajmuje się stosem sieciowym, aby odbierać dane z internetu, wątek pamięci, który kontroluje dostęp do plików, i nie tylko. Gdy wpisujesz adres URL na pasku adresu, dane wejściowe są obsługiwane przez wątek UI procesu przeglądarki.
Prosta nawigacja
Krok 1. Obsługa danych wejściowych
Gdy użytkownik zaczyna pisać w pasku adresu, pierwszy wątek interfejsu użytkownika pyta „Czy to jest wyszukiwane hasło, czy URL?”. W Chrome pasek adresu jest również polem do wprowadzania danych wyszukiwania, więc wątek UI musi zostać przeanalizowany i zdecydować, czy przekierować Cię do wyszukiwarki, czy do żądanej witryny.
Krok 2. Rozpocznij nawigację
Gdy użytkownik naciśnie klawisz Enter, wątek UI inicjuje wywołanie sieciowe w celu pobrania treści witryny. W rogu karty wyświetla się ikona wczytywania, a wątek sieci przechodzi przez odpowiednie protokoły, takie jak wyszukiwanie DNS i nawiązuje połączenie TLS dla żądania.
W tym momencie wątek sieciowy może otrzymać nagłówek przekierowania serwera, taki jak HTTP 301. W takim przypadku wątek sieci komunikuje się z wątkiem UI, którego serwer żąda przekierowania. Następnie jest wysyłane kolejne żądanie adresu URL.
Krok 3. Przeczytaj odpowiedź
Gdy zacznie przychodzić treść odpowiedzi (ładunek), w razie potrzeby wątek sieciowy sprawdza kilka pierwszych bajtów strumienia. Nagłówek Content-Type odpowiedzi powinien zawierać informacje o typie danych, ale ponieważ może ich brakować lub być nieprawidłowe, w tym miejscu odbywa się sniffing typu MIME. Jest to „podejrzana firma”, o czym wspomniano w kodzie źródłowym. Możesz przeczytać komentarz, aby zobaczyć, jak różne przeglądarki traktują pary typ treści i ładunek.
Jeśli odpowiedź jest plikiem HTML, kolejnym krokiem jest przekazanie danych do mechanizmu renderowania. Jeśli jest to plik ZIP lub inny plik, oznacza to, że jest to żądanie pobrania, więc dane muszą przekazać do menedżera pobierania.
Tutaj odbywa się też kontrola SafeBrowsing. Jeśli domena i dane odpowiedzi wydają się być zgodne ze znaną szkodliwą witryną, alert o wątku sieciowym wyświetli stronę z ostrzeżeniem. Dodatkowo przeprowadzamy CCCblokowania (C), aby zapewnić, że poufne dane z innych witryn nie trafią do procesu renderowania.
Krok 4. Znajdź proces renderowania
Po zakończeniu weryfikacji, a wątek sieci będzie mieć pewność, że przeglądarka powinna przejść do żądanej witryny, a wątek sieci informuje wątek UI, że dane są gotowe. Wątek UI znajduje następnie proces renderowania, który kontynuuje renderowanie strony.
Uzyskanie odpowiedzi na żądanie sieciowe może trwać kilkaset milisekund, dlatego zastosowaliśmy optymalizację w celu przyspieszenia tego procesu. Gdy w kroku 2 wątek UI wysyła do wątku sieci żądanie adresu URL, wie już, do której witryny prowadzi. Wątek UI próbuje aktywnie znaleźć lub uruchomić proces renderowania równolegle do żądania sieciowego. Dzięki temu, jeśli wszystko pójdzie zgodnie z oczekiwaniami, mechanizm renderowania będzie już w pozycji gotowości, gdy wątek sieciowy odebrał dane. Ten proces gotowości może nie być używany, jeśli nawigacja między witrynami jest przekierowywana. W takim przypadku konieczne może być zastosowanie innego procesu.
Krok 5. Zatwierdź nawigację
Dane i proces renderowania są już gotowe, więc z procesu przeglądarki do mechanizmu renderowania jest wysyłany IPC w celu zatwierdzenia nawigacji. Strumień danych przekazuje też strumień danych, dzięki czemu proces renderowania może dalej odbierać dane HTML. Gdy proces przeglądarki usłyszy potwierdzenie, że zatwierdzenie miało miejsce w procesie renderowania, nawigacja dobiega końca i rozpoczyna się faza wczytywania dokumentu.
Pasek adresu jest teraz zaktualizowany, a wskaźnik bezpieczeństwa i interfejs ustawień witryny odzwierciedlają informacje o nowej stronie. Historia sesji na tej karcie zostanie zaktualizowana, więc przyciski Wstecz/Dalej będą przechodzić przez odwiedzaną właśnie witrynę. Aby ułatwić przywracanie kart/sesji po zamknięciu karty lub okna, historia sesji jest przechowywana na dysku.
Dodatkowy krok: wstępne wczytywanie zakończone
Po zatwierdzeniu nawigacji proces renderowania kontynuuje wczytywanie zasobów i renderuje stronę. Cały proces zostanie szczegółowo omówiony w następnym poście. Gdy mechanizm renderowania „zakończy” renderowanie, wysyła kod IPC z powrotem do procesu przeglądarki (dzieje się to po wywołaniu wszystkich zdarzeń onload
we wszystkich ramkach na stronie i zakończeniu wykonywania). W tym momencie wątek interfejsu zatrzymuje wskaźnik postępu ładowania na karcie.
Mówię „finishes”, ponieważ od tego momentu JavaScript po stronie klienta wciąż może wczytać dodatkowe zasoby i wyrenderować nowe widoki.
Przechodzenie do innej witryny
To już wszystko. Co się jednak stanie, jeśli użytkownik ponownie wpisze inny adres URL na pasku adresu? Cóż, proces przeglądarki wykonuje te same kroki, aby przejść do innej witryny.
Zanim będzie to możliwe, musi sprawdzić aktualnie wyrenderowaną witrynę, czy zależy jej na zdarzeniu beforeunload
.
beforeunload
może utworzyć alert „Opuścić tę witrynę?”, gdy próbujesz opuścić lub zamknąć kartę.
Cała zawartość karty, w tym kod JavaScript, jest obsługiwana przez mechanizm renderowania, więc gdy pojawia się nowe żądanie nawigacji, proces przeglądarki musi kontrolować bieżący mechanizm renderowania.
Jeśli nawigacja została zainicjowana przez proces renderowania (np. użytkownik kliknął link lub uruchomił się kod JavaScript po stronie klienta window.location = "https://newsite.com"
), mechanizm renderowania najpierw sprawdza moduły obsługi beforeunload
. Następnie przebiega tak samo jak nawigacja zainicjowana przez proces przeglądarki. Jedyna różnica polega na tym, że żądanie nawigacji jest inicjowane z procesu renderowania do procesu przeglądarki.
Gdy nowa nawigacja zostanie przekierowana do innej witryny niż aktualnie renderowana, wywołany jest oddzielny proces renderowania, który obsługuje nową nawigację, a bieżący proces renderowania jest zachowywany w celu obsługi zdarzeń takich jak unload
. Aby dowiedzieć się więcej, przeczytaj omówienie stanów cyklu życia strony i dowiedz się, jak dołączać do zdarzeń za pomocą interfejsu Page Lifecycle API.
W przypadku skryptu service worker
Jedną z niedawnych zmian w tym procesie nawigacji jest wprowadzenie skryptu service worker. Skrypt service worker pozwala zapisać sieciowy serwer proxy w kodzie aplikacji, co daje programistom stron internetowych większą kontrolę nad tym, co ma być zapisywane lokalnie w pamięci podręcznej, a kiedy z siecią. Jeśli skrypt service worker jest ustawiony na wczytywanie strony z pamięci podręcznej, nie ma potrzeby żądania danych z sieci.
Pamiętaj, że skrypt service worker to kod JavaScript uruchamiany w procesie renderowania. Gdy jednak pojawia się żądanie nawigacji, skąd przeglądarka może wiedzieć, że witryna ma skrypt service worker?
Gdy skrypt service worker jest zarejestrowany, jego zakres jest zachowywany jako punkt odniesienia (więcej informacji o zakresie znajdziesz w tym artykule). Gdy następuje nawigacja, wątek sieci sprawdza domenę pod kątem zarejestrowanych zakresów skryptu service worker. Jeśli skrypt service worker jest zarejestrowany dla tego adresu URL, wątek interfejsu znajduje proces renderowania w celu wykonania kodu skryptu service worker. Skrypt service worker może wczytywać dane z pamięci podręcznej, eliminując potrzebę wysyłania żądań danych do sieci lub żądając nowych zasobów z sieci.
Wstępne wczytywanie nawigacji
Widać, że podróż w obie strony między procesem przeglądarki a mechanizmem renderowania może spowodować opóźnienia, jeśli skrypt service worker w końcu zdecyduje się wysłać żądanie danych do sieci. Wstępne wczytywanie nawigacji to mechanizm przyspieszający ten proces przez ładowanie zasobów równolegle do uruchamiania skryptu service worker. Oznacza on te żądania nagłówkiem, dzięki czemu serwery mogą wysyłać inne treści w odpowiedzi na żądania, np. tylko zaktualizowane dane, a nie cały dokument.
Podsumowanie
W tym poście omówiliśmy, co dzieje się podczas nawigacji i jak kod Twojej aplikacji internetowej, np. nagłówki odpowiedzi i JavaScript po stronie klienta, współdziałają z przeglądarką. Znajomość czynności, jakie musi wykonać przeglądarka, aby pobrać dane z sieci, ułatwia zrozumienie, dlaczego tak się stało. W następnym poście dowiemy się, jak przeglądarka ocenia kod HTML/CSS/JavaScript pod kątem renderowania stron.
Podobał Ci się post? Jeśli masz jakieś pytania lub sugestie dotyczące kolejnego posta, chętnie poznam Twoją opinię w sekcji komentarzy poniżej lub na Twitterze – @kosamari.