Chrome頁面導航過程(Part2)
本系列文章從內部剖析了 Chrome 瀏覽器的程序、執行緒架構設計,各部原理等基礎知識,梳理了瀏覽器是怎樣將你的程式碼變成網站的,解開某個特定技術為什麼可以提高效能的疑問。本文是這個系列的第二篇,講述了 Chome 瀏覽器從您鍵入 URL,從 Internet 獲取資料並開始展示頁面前的過程中發生了什麼 。我們把這一過程稱作 導航
。
本系列文章共 4 篇,原文釋出在 ofollow,noindex">Google 開發者部落格 ,作者 Mariko Kosaka 。文章中涉及 非中文區域網友好連結
請讀者自行解決。
讓我們看一個常見的操作場景:您在瀏覽器中鍵入 URL,然後瀏覽器從 Internet 獲取資料並顯示頁面。在這篇文章中,我們將重點關注使用者請求網站的部分以及瀏覽器準備呈現頁面的部分。
它從瀏覽器程序(Browser Process)開始
上面是瀏覽器 UI,下面是UI、網路和儲存執行緒的程序圖
正如我在 第1部分中所述:CPU,GPU,記憶體和多程序架構 所術,選項卡外部的所有內容都由瀏覽器程序處理。瀏覽器程序含有多個執行緒如: UI 執行緒 繪製瀏覽器的按鈕和輸入欄位, 網路執行緒 從網路接受和傳送資料, 儲存執行緒 管理對檔案的訪問控制等。 當您在位址列中鍵入URL時,您的輸入將由瀏覽器程序的 UI 執行緒處理。
一個簡單的載入過程
第一步:處理輸入
當用戶開在位址列開始輸入時,UI 執行緒首先要判斷“這是搜尋查詢還是URL?”。 在 Chrome 中,位址列也是搜尋輸入框,因此UI執行緒需要解析並決定是將您的輸入傳送到搜尋引擎還是傳送到您請求的網站。
UI 執行緒判斷“這是搜尋查詢還是URL?”
第二步:開始載入
當用戶點選 Enter 時,UI 執行緒發起網路請求以獲取站點內容。載入進度條顯示在選項卡左上角,網路執行緒通過適當的協議,如 DNS,為請求建立TLS連線。
UI 執行緒告訴網路執行緒載入 mysite.com
此時網路執行緒可能接收到 HTTP 301 這樣的伺服器重定向頭。在這種情況下,網路執行緒將重定向告知 UI執行緒。 然後,將啟動另一個 URL 請求。
第三步:讀取響應
一旦響應主體(有效負載)開始接收,網路執行緒會在必要時檢視網路流的前幾個位元組。確定響應的 Content-Type 頭以說明響應是什麼型別的資料,由於它可能丟失或錯誤,所以在這裡完成 MIME 型別嗅探 。 這就是 Chromium 原始碼 中註釋的tricky業務。 您可以閱讀註釋,以瞭解不同的瀏覽器如何處理 Content-Type 欄位。
響應中的 Content-Type 和有效負載
如果響應是HTML檔案,那麼下一步就是將資料傳遞給渲染器程序,但如果它是 zip 檔案或其他檔案,則表示這是個下載請求,需要將資料傳遞給下載管理器。
網路執行緒檢查來自合法網站的資料是不是 HTML
這也是 SafeBrowsing 檢查發生的時候。 如果域和響應資料似乎與已知的惡意站點匹配,則網路執行緒會發出警告以顯示警告頁面。 此外,發生 跨源讀取(CORB) 時敏感的跨站資料不會進入渲染器程序。
第四步:渲染器程序
完成所有檢查並且網路執行緒確信瀏覽器應載入所請求的站點後,網路執行緒會告知 UI 執行緒資料已準備就緒。 然後,UI 執行緒告知渲染器程序以進行網頁的渲染。
網路執行緒告訴UI執行緒通知渲染器執行緒
由於網路請求可能需要幾百毫秒才能得到響應,因此這裡對這一過程做了優化。 當 UI 執行緒在第二步向網路執行緒傳送 URL 請求時,它已經知道他們正在導航到哪個站點。 UI執行緒嘗試與網路請求並行地主動查詢或啟動渲染器程序。 這樣,如果一切按預期進行,則當網路執行緒接收資料時,渲染器程序已處於備用位置。 如果得到重定向並且跨站點,則可能不會使用此備用程序,在這種情況下可能需要不同的程序。
第五步:提交載入
現在資料和渲染器程序已準備就緒,一個 IPC 將從瀏覽器程序傳送到渲染器程序以提交載入。 網路還傳遞資料流,因此渲染器程序可以繼續接收HTML資料。 一旦瀏覽器程序接收到渲染器程序確認提交,導航就完成了,文件載入階段就開始了。
此時,位址列會更新,安全指示器和站點設定 UI 會反映新頁面的站點資訊。 選項卡的會話歷史記錄、後退、前進按鈕將更新。 為了在關閉選項卡或視窗後恢復選項卡狀態,會話歷史記錄儲存在磁碟上。
瀏覽器和渲染器程序之間的IPC
額外步驟:初始載入完成
提交導航後,渲染器程序繼續載入資源並呈現頁面。 我們將在下一篇文章中詳細介紹這個階段的情況。 一旦渲染器程序“完成”渲染,它就會將一個 IPC 傳送回瀏覽器程序(這是在所有 onload 事件觸發了頁面中的所有幀並完成執行之後)。 此時,UI 執行緒會停止選項卡上的載入進度條。
我說“完成”加引號,是因為客戶端 JavaScript 仍然可以載入額外的資源並在此之後呈現新的檢視。
渲染器程序通過 IPC 告訴 UI 執行緒 loaded
導航到其他站點
簡單的導航完成了!但是如果使用者再次將不同的URL放到位址列會發生什麼?瀏覽器程序會通過相同的步驟導航到不同的站點。但在它做這一點之前,需要檢查當前渲染的站點是否監聽了 beforeunload 事件。
beforeunload 當您嘗試導航或關閉選項卡時 可以建立“確認離開這個網站嗎?” 發出警報。 包含 JavaScript 程式碼的選項卡內的所有內容都由渲染器程序處理,因此瀏覽器程序必須在新導航請求進入時檢查當前渲染器程序。
警告:不要任意監聽 beforeunload。因為它在啟動導航之前需要執行處理程式。應僅在需要時新增此事件監聽,例如需要警告使用者他們可能會丟失資料。
瀏覽器程序告訴渲染器程序將要導航到新頁面
如果導航是從渲染器程序啟動的(如使用者單擊連結或客戶端 JavaScript 執行 window.location =“https://newsite.com”
),則渲染器程序首先檢查 beforeunload 處理程式。 然後出發與瀏覽器程序發起導航相同的過程。 唯一的區別是導航請求從渲染器程序傳送到瀏覽器程序。
當新導航進入與當前不同的站點時,將呼叫單獨的渲染器程序來處理新導航,同時保持當前渲染器程序以處理 unload
等事件。 有關更多資訊,請參閱 頁面生命週期狀態概述 以及如何使用 Page Lifecycle API
瀏覽器程序通過 IPC 啟動新的渲染程序以導航到新網站同時讓當前渲染程序處理 unload
Service Worker 的情況
最近對導航過程的一個變動是引入了 service worker
。 service worker 是一種在應用程式程式碼中編寫網路代理的方法;允許 Web 開發人員更好地控制本地快取內容以及何時從網路獲取新資料。如果將 service worker 設定為從快取載入頁面,則無需從網路請求資料。
要記住重要的是 service worker 是在渲染器程序中執行的 JavaScript 程式碼。但是當導航請求進入時,瀏覽器程序如何知道該站點有服務工作者?
註冊 service worker 時,將保留 service worker 的作用域作為參考(您可以在 service worker生命週期 中檢視更多資訊)。當導航發生時,網路執行緒根據註冊的 service worker 範圍檢查域 URL,如果為該 URL 註冊了 service worker,則 UI 執行緒找到渲染器程序以執行服務工作者程式碼。 service worker 可以從快取載入資料,無需從網路請求資料,或者可以從網路請求新資源。
在瀏覽器程序中啟動UI執行緒,啟動渲染器程序來處理service worker; 然後,渲染器程序中的工作執行緒從網路請求資料
導航預載入
可以看到,如果 service worker 最終決定從網路請求資料,則瀏覽器程序和渲染器程序之間的往返可能會導致延遲。 導航預載入 是一種通過與 service worker 並行啟動載入資源來加速此過程的機制。 它用請求頭標記這些請求,允許伺服器決定為這些請求響應不同的內容; 例如,只更新資料而不是傳送完整的文件。
瀏覽器程序中的UI執行緒啟動渲染器程序以處理service worker,同時並行啟動網路請求
總結
在這篇文章中,我們研究了導航過程中發生的情況以及響應頭、客戶端 JavaScript 等 Web 應用程式程式碼如何與瀏覽器互動的。 瞭解了瀏覽器通過網路獲取資料的步驟,可以更容易地理解為什麼開發導航預載等 API。 在下一篇文章中,我們將深入探討瀏覽器如何載入 HTML、CSS、JavaScript 以呈現頁面。