Was passiert bei der Navigation?
Dies ist Teil 2 einer vierteiligen Blogreihe, in der wir uns die Funktionsweise von Chrome genauer ansehen. Im vorherigen Beitrag haben wir uns angesehen, wie verschiedene Prozesse und Threads verschiedene Teile eines Browsers verarbeiten. In diesem Beitrag gehen wir genauer darauf ein, wie die einzelnen Prozesse und Threads kommunizieren, um eine Website anzuzeigen.
Sehen wir uns einen einfachen Anwendungsfall für das Surfen im Web an: Sie geben eine URL in einen Browser ein. Der Browser ruft dann Daten aus dem Internet ab und zeigt eine Seite an. In diesem Beitrag konzentrieren wir uns auf den Teil, in dem ein Nutzer eine Website anfordert und der Browser sich darauf vorbereitet, eine Seite zu rendern. Dieser Vorgang wird auch als Navigation bezeichnet.
Es beginnt mit einem Browserprozess

Wie wir in Teil 1: CPU, GPU, Arbeitsspeicher und mehrstufige Architektur besprochen haben, wird alles außerhalb eines Tabs vom Browserprozess verarbeitet. Der Browserprozess umfasst Threads wie den UI-Thread, der Schaltflächen und Eingabefelder des Browsers zeichnet, den Netzwerk-Thread, der sich um den Netzwerkstack zum Empfangen von Daten aus dem Internet kümmert, und den Speicher-Thread, der den Zugriff auf die Dateien steuert. Wenn Sie eine URL in die Adressleiste eingeben, wird Ihre Eingabe vom UI-Thread des Browserprozesses verarbeitet.
Eine einfache Navigation
Schritt 1: Eingabe verarbeiten
Wenn ein Nutzer etwas in die Adressleiste eingibt, wird zuerst im UI-Thread gefragt: „Ist das eine Suchanfrage oder eine URL?“ In Chrome ist die Adressleiste auch ein Sucheingabefeld. Daher muss der UI-Thread die Eingabe analysieren und entscheiden, ob Sie zu einer Suchmaschine oder zur von Ihnen angeforderten Website weitergeleitet werden.

Schritt 2: Navigation starten
Wenn ein Nutzer die Eingabetaste drückt, initiiert der UI-Thread einen Netzwerkaufruf, um Websiteinhalte abzurufen. In der Ecke eines Tabs wird ein Ladebalken angezeigt und der Netzwerk-Thread führt entsprechende Protokolle durch, z. B. DNS-Lookup und TLS-Verbindung für die Anfrage.

An diesem Punkt kann der Netzwerk-Thread einen Server-Weiterleitungsheader wie HTTP 301 erhalten. In diesem Fall teilt der Netzwerk-Thread dem UI-Thread mit, dass der Server eine Weiterleitung anfordert. Dann wird eine weitere URL-Anfrage gestartet.
Schritt 3: Antwort lesen

Sobald der Antworttext (Nutzlast) eingeht, prüft der Netzwerk-Thread bei Bedarf die ersten Bytes des Streams. Der Content-Type-Header der Antwort sollte angeben, um welche Art von Daten es sich handelt. Da er jedoch möglicherweise fehlt oder falsch ist, wird hier MIME-Typ-Sniffing durchgeführt. Dies ist eine „schwierige Angelegenheit“, wie im Quellcode kommentiert. Im Kommentar erfahren Sie, wie verschiedene Browser Inhaltstyp-/Nutzlastpaare behandeln.
Wenn die Antwort eine HTML-Datei ist, werden die Daten im nächsten Schritt an den Rendering-Prozess übergeben. Bei einer ZIP-Datei oder einer anderen Datei handelt es sich jedoch um einen Downloadanfrage, sodass die Daten an den Downloadmanager übergeben werden müssen.

Hier erfolgt auch die SafeBrowsing-Prüfung. Wenn die Domain und die Antwortdaten mit einer bekannten schädlichen Website übereinstimmen, wird über den Netzwerk-Thread eine Warnseite angezeigt. Außerdem wird Cross Origin Read Blocking (CORB) geprüft, um sicherzustellen, dass sensible websiteübergreifende Daten nicht an den Rendering-Prozess gelangen.
Schritt 4: Rendererprozess finden
Sobald alle Prüfungen abgeschlossen sind und der Netzwerk-Thread sicher ist, dass der Browser zur angeforderten Website wechseln soll, teilt der Netzwerk-Thread dem UI-Thread mit, dass die Daten bereit sind. Der UI-Thread sucht dann einen Renderer-Prozess, um das Rendering der Webseite fortzusetzen.

Da es mehrere hundert Millisekunden dauern kann, bis eine Antwort auf die Netzwerkanfrage zurückgegeben wird, wird eine Optimierung angewendet, um diesen Vorgang zu beschleunigen. Wenn der UI-Thread in Schritt 2 eine URL-Anfrage an den Netzwerk-Thread sendet, weiß er bereits, auf welche Website er zugreift. Der UI-Thread versucht, parallel zur Netzwerkanfrage proaktiv einen Renderer-Prozess zu finden oder zu starten. So befindet sich ein Rendererprozess, wenn alles wie erwartet funktioniert, bereits im Standby, wenn der Netzwerk-Thread Daten empfängt. Dieser Standby-Prozess wird möglicherweise nicht verwendet, wenn die Navigation seitenübergreifend weiterleitet. In diesem Fall ist möglicherweise ein anderer Prozess erforderlich.
Schritt 5: Navigation committen
Nachdem die Daten und der Renderer-Prozess bereit sind, wird eine IPC vom Browserprozess an den Renderer-Prozess gesendet, um die Navigation zu bestätigen. Außerdem gibt er den Datenstream weiter, damit der Rendering-Prozess weiterhin HTML-Daten empfangen kann. Sobald der Browserprozess eine Bestätigung erhält, dass die Commit-Aktion im Rendererprozess stattgefunden hat, ist die Navigation abgeschlossen und die Phase des Dokumentladens beginnt.
In diesem Moment wird die Adressleiste aktualisiert und der Sicherheitsindikator und die Benutzeroberfläche der Websiteeinstellungen spiegeln die Websiteinformationen der neuen Seite wider. Der Sitzungsverlauf für den Tab wird aktualisiert, sodass Sie mit den Schaltflächen „Zurück“ und „Vorwärts“ die Website aufrufen können, auf die Sie gerade zugegriffen haben. Damit Sie Tabs und Sitzungen leichter wiederherstellen können, wenn Sie einen Tab oder ein Fenster schließen, wird der Sitzungsverlauf auf dem Laufwerk gespeichert.

Zusätzlicher Schritt: Anfänglicher Ladevorgang abgeschlossen
Sobald die Navigation festgelegt wurde, lädt der Rendering-Prozess weiter Ressourcen und rendert die Seite. Im nächsten Beitrag gehen wir genauer darauf ein, was in dieser Phase passiert. Sobald der Rendering-Prozess abgeschlossen ist, sendet er eine IPC zurück an den Browserprozess. Dies geschieht, nachdem alle onload
-Ereignisse für alle Frames auf der Seite ausgelöst und ausgeführt wurden. An diesem Punkt beendet der UI-Thread das Ladesymbol auf dem Tab.
Ich sage „beendet“, weil clientseitiges JavaScript nach diesem Punkt noch zusätzliche Ressourcen laden und neue Ansichten rendern kann.

Eine andere Website aufrufen
Die einfache Navigation war fertig. Was passiert aber, wenn ein Nutzer wieder eine andere URL in die Adressleiste eingibt? Der Browserprozess durchläuft dieselben Schritte, um die andere Website aufzurufen.
Bevor das möglich ist, muss er jedoch auf der aktuell gerenderten Website prüfen, ob das Ereignis beforeunload
berücksichtigt werden soll.
beforeunload
kann die Warnung „Diese Website verlassen?“ anzeigen, wenn Sie versuchen, die Seite zu verlassen oder den Tab zu schließen.
Alles auf einem Tab, einschließlich Ihres JavaScript-Codes, wird vom Renderer-Prozess verarbeitet. Daher muss der Browserprozess den aktuellen Renderer-Prozess prüfen, wenn eine neue Navigationsanfrage eingeht.

Wenn die Navigation vom Renderer-Prozess aus gestartet wurde (z. B. wenn der Nutzer auf einen Link geklickt oder clientseitiges JavaScript ausgeführt hat), prüft der Renderer-Prozess zuerst beforeunload
-Handler.window.location = "https://newsite.com"
Anschließend durchläuft sie denselben Prozess wie die vom Browser initiierte Navigation. Der einzige Unterschied besteht darin, dass die Navigationsanfrage vom Rendererprozess an den Browserprozess gesendet wird.
Wenn die neue Navigation zu einer anderen Website als der aktuell gerenderten Website führt, wird ein separater Rendering-Prozess aufgerufen, um die neue Navigation zu verarbeiten. Der aktuelle Rendering-Prozess wird beibehalten, um Ereignisse wie unload
zu verarbeiten. Weitere Informationen finden Sie unter Übersicht über die Status des Seitenlebenszyklus und API für den Seitenlebenszyklus.

Für Service Worker
Eine aktuelle Änderung an diesem Navigationsprozess ist die Einführung von Dienst-Workern. Mit Service Workern können Sie einen Netzwerkproxy in Ihren Anwendungscode schreiben. So haben Webentwickler mehr Kontrolle darüber, was lokal im Cache gespeichert werden soll und wann neue Daten aus dem Netzwerk abgerufen werden sollen. Wenn der Dienst-Worker so konfiguriert ist, dass die Seite aus dem Cache geladen wird, müssen die Daten nicht vom Netzwerk angefordert werden.
Wichtig ist, dass ein Dienst-Worker JavaScript-Code ist, der in einem Renderer-Prozess ausgeführt wird. Aber woher weiß ein Browserprozess, wenn die Navigationsanfrage eingeht, dass die Website einen Service Worker hat?

Wenn ein Dienstarbeiter registriert wird, wird sein Umfang als Referenz beibehalten. Weitere Informationen zum Umfang finden Sie im Artikel Der Dienstarbeiter-Lebenszyklus. Bei einer Navigation prüft der Netzwerk-Thread die Domain anhand der registrierten Service Worker-Bereiche. Wenn für diese URL ein Service Worker registriert ist, sucht der UI-Thread einen Renderer-Prozess, um den Service Worker-Code auszuführen. Der Service Worker kann Daten aus dem Cache laden, sodass keine Daten mehr vom Netzwerk angefordert werden müssen. Er kann aber auch neue Ressourcen vom Netzwerk anfordern.

Navigationsvorabladen
Dieser Hin- und Rückweg zwischen dem Browserprozess und dem Rendererprozess kann zu Verzögerungen führen, wenn der Service Worker schließlich entscheidet, Daten aus dem Netzwerk anzufordern. Navigations-Preload ist ein Mechanismus, mit dem dieser Vorgang beschleunigt wird, indem Ressourcen parallel zum Start des Dienstarbeiters geladen werden. Diese Anfragen werden mit einem Header gekennzeichnet, sodass Server entscheiden können, für diese Anfragen andere Inhalte zu senden, z. B. nur aktualisierte Daten anstelle eines vollständigen Dokuments.

Zusammenfassung
In diesem Beitrag haben wir uns angesehen, was bei einer Navigation passiert und wie der Code Ihrer Webanwendung, z. B. Antwortheader und clientseitiges JavaScript, mit dem Browser interagiert. Wenn Sie wissen, welche Schritte der Browser durchläuft, um Daten aus dem Netzwerk abzurufen, können Sie leichter nachvollziehen, warum APIs wie das Navigations-Preloading entwickelt wurden. Im nächsten Beitrag sehen wir uns an, wie der Browser unser HTML/CSS/JavaScript zum Rendern von Seiten auswertet.
Hat Ihnen der Beitrag gefallen? Wenn du Fragen oder Vorschläge für den nächsten Beitrag hast, kannst du dich unten in den Kommentaren oder auf Twitter unter @kosamari melden.
Nächster Schritt: Die Funktionsweise eines Renderer-Prozesses