導覽過程中會發生的情況
這是部落格系列文章 (共 4 篇) 的第 2 篇,將探討 Chrome 的內部運作方式。在上一篇文章中,我們探討了不同的程序和執行緒如何處理瀏覽器的不同部分。在本篇文章中,我們將深入探討各個程序和執行緒如何溝通,以便顯示網站。
我們來看看網路瀏覽的簡單用途:您在瀏覽器中輸入網址,瀏覽器就會從網路擷取資料並顯示網頁。在本篇文章中,我們將著重於使用者要求網站,以及瀏覽器準備轉譯網頁 (又稱為導覽) 的部分。
這項作業會從瀏覽器程序開始

如第 1 部分:CPU、GPU、記憶體和多程序架構所述,分頁以外的所有內容都由瀏覽器程序處理。瀏覽器程序包含多個執行緒,例如負責繪製瀏覽器按鈕和輸入欄位的 UI 執行緒、負責處理網路堆疊以接收網際網路資料的網路執行緒,以及負責控制檔案存取權的儲存執行緒等。當您在網址列中輸入網址時,瀏覽器程序的 UI 執行緒會處理輸入內容。
簡易導覽
步驟 1:處理輸入內容
當使用者開始在網址列中輸入內容時,UI 執行緒首先會詢問「這是搜尋查詢還是網址?」。在 Chrome 中,網址列也是搜尋輸入欄位,因此 UI 執行緒需要解析並決定是否要將您導向搜尋引擎,或您要求的網站。

步驟 2:開始導航
使用者按下 Enter 鍵時,UI 執行緒會啟動網路呼叫,以便取得網站內容。載入旋轉圖示會顯示在分頁角落,網路執行緒會執行適當的通訊協定,例如 DNS 查詢和為要求建立 TLS 連線。

此時,網路執行緒可能會收到 HTTP 301 等伺服器重新導向標頭。在這種情況下,網路執行緒會與 UI 執行緒通訊,指出伺服器要求重新導向。接著,系統會啟動另一個網址要求。
步驟 3:朗讀回覆

回應主體 (酬載) 開始傳入後,網路執行緒會視需要查看串流的前幾個位元組。回應的 Content-Type 標頭應會指出資料類型,但由於標頭可能遺漏或錯誤,因此會執行 MIME 類型嗅探。這是「棘手的業務」,如原始碼中的註解所述。您可以參閱該註解,瞭解不同瀏覽器如何處理內容類型/酬載組合。
如果回應是 HTML 檔案,則下一步是將資料傳遞至轉譯器程序;如果是 ZIP 檔案或其他檔案,則表示這是下載要求,因此需要將資料傳遞至下載管理工具。

這也是SafeBrowsing 檢查的發生位置。如果網域和回應資料似乎與已知的惡意網站相符,網路執行緒就會發出警示,顯示警告頁面。此外,系統會執行Cross Origin Read Blocking (CORB) 檢查,確保敏感的跨網站資料不會傳送至轉譯器程序。
步驟 4:找出轉譯器程序
完成所有檢查後,如果 Network 執行緒確信瀏覽器應導向要求的網站,就會通知 UI 執行緒資料已就緒。接著,UI 執行緒會尋找轉譯器程序,以便繼續轉譯網頁。

由於網路要求可能需要數百毫秒才能傳回回應,因此我們會套用最佳化方式來加快這個程序。當 UI 執行緒在步驟 2 中將網址要求傳送至網路執行緒時,它已知道要前往哪個網站。UI 執行緒會嘗試主動尋找或啟動與網路要求並行的轉譯器程序。如此一來,如果一切正常,網路執行緒收到資料時,轉譯器程序就會處於待命狀態。如果導覽重新導向跨網站,系統可能不會使用這個待命程序,而需要使用其他程序。
步驟 5:提交導覽
資料和轉譯器程序都已就緒,因此從瀏覽器程序傳送 IPC 至轉譯器程序,以便提交導覽。它也會傳遞資料串流,讓轉譯器程序可以持續接收 HTML 資料。一旦瀏覽器程序收到確認訊息,表示在轉譯器程序中已完成提交,瀏覽器程序就會完成導覽,並開始文件載入階段。
此時,系統會更新網址列,並在安全性指標和網站設定 UI 中顯示新網頁的網站資訊。分頁的工作階段記錄會更新,因此「前往上一個」/「前往下一個」按鈕會逐一瀏覽剛前往的網站。為了在關閉分頁或視窗時便於還原分頁/工作階段,系統會將工作階段記錄儲存在磁碟上。

額外步驟:初始載入完成
導覽完成後,轉譯器程序會繼續載入資源並轉譯網頁。我們會在下一篇文章中詳細說明這個階段的情況。轉譯器程序「完成」轉譯後,就會將 IPC 傳回至瀏覽器程序 (這是在網頁中的所有影格觸發所有 onload
事件並完成執行後)。此時,UI 執行緒會停止分頁上的載入旋轉圖示。
我說「完成」是因為用戶端 JavaScript 仍可在這個時間點後載入其他資源,並轉換為新檢視畫面。

前往其他網站
簡易導覽已完成!但如果使用者再次將不同網址放入網址列,會發生什麼情況?瀏覽器程序會透過相同的步驟前往其他網站。但在執行這項操作前,它必須先向目前顯示的網站查詢是否需要 beforeunload
事件。
beforeunload
可在您嘗試離開或關閉分頁時,建立「離開這個網站嗎?」快訊。分頁內的所有內容 (包括 JavaScript 程式碼) 都由轉譯器程序處理,因此瀏覽器程序必須在收到新的導覽要求時,向目前的轉譯器程序進行檢查。

如果導覽是由轉譯器程序啟動 (例如使用者按一下連結,或是用戶端 JavaScript 已執行 window.location = "https://newsite.com"
),轉譯器程序會先檢查 beforeunload
處理常式。接著,它會經歷與瀏覽器程序相同的程序,啟動導覽。唯一的差異在於導覽要求是從轉譯器程序啟動至瀏覽器程序。
如果新導覽網頁與目前顯示的網頁不同,系統會呼叫個別的轉譯程序來處理新導覽網頁,同時保留目前的轉譯程序來處理 unload
等事件。詳情請參閱頁面生命週期狀態總覽,以及如何使用頁面生命週期 API鉤掛事件。

如果是 Service Worker
這項導覽程序最近的變更之一,就是引入服務工作者。Service Worker 是一種在應用程式程式碼中編寫網路 Proxy 的方法,可讓網頁開發人員進一步控管要快取的內容,以及從網路取得新資料的時間。如果服務工作者已設為從快取載入網頁,就不需要從網路要求資料。
請務必記住,服務工作者是執行在轉譯器程序中的 JavaScript 程式碼。不過,當導覽要求傳入時,瀏覽器程序如何得知網站有服務工作者?

註冊服務工作者時,服務工作者的範圍會保留做為參照 (如要進一步瞭解範圍,請參閱這篇「服務工作者生命週期」文章)。導覽發生時,網路執行緒會檢查網域是否與已註冊的服務工作者範圍相符,如果已為該網址註冊服務工作者,UI 執行緒會尋找轉譯器程序,以便執行服務工作者程式碼。服務工作站可能會從快取載入資料,因此不必從網路要求資料,也可能會從網路要求新的資源。

導覽預先載入
您可以看到,如果服務工作者最終決定從網路要求資料,瀏覽器程序和轉譯器程序之間的來回通訊可能會導致延遲。Navigation Preload 是一種機制,可在服務工作者啟動時並行載入資源,加快這個程序。這項功能會為這些要求加上標頭,讓伺服器決定為這些要求傳送不同的內容,例如只傳送更新的資料,而非完整文件。

總結
在本篇文章中,我們將探討導覽期間發生的情況,以及網頁應用程式程式碼 (例如回應標頭和用戶端 JavaScript) 如何與瀏覽器互動。瞭解瀏覽器從網路取得資料的步驟,有助於您瞭解為何開發導覽預先載入等 API。在下一篇文章中,我們將深入探討瀏覽器如何評估 HTML/CSS/JavaScript 以轉譯網頁。
你喜歡這篇文章嗎?如有任何問題或建議,歡迎在下方的留言區留言,或在 Twitter 上傳送訊息給 @kosamari。