現代瀏覽器探祕(part2):導航

翻譯:瘋狂的技術宅
原文: https://developers.google.com...

本文首發微信公衆號:jingchengyideng
點擊下面連接查看其它章節文章web


導航時都發生了什麼

這是關於Chrome內部工做原理系列的第2部分。 在上一篇文章中,咱們研究了不一樣的進程與線程是怎樣如何處理瀏覽器不一樣部分的。 在這一篇中,咱們將會深刻研究每一個進程和線程是如何進行通訊以顯示網站內容的。api

讓咱們看一下Web瀏覽的簡單用例:你在瀏覽器中鍵入URL,而後瀏覽器從Internet獲取數據並顯示頁面。 在這篇文章中,咱們將重點關注用戶請求網站的部分以及瀏覽器準備呈現頁面的部分 - 也稱爲導航。瀏覽器

從瀏覽器進程開始

正如咱們在第1部分(CPU,GPU,內存和多進程架構 )中所描述的,選項卡外部的全部內容都由瀏覽器進程處理。 瀏覽器進程具備不少線程,好比於UI線程用於繪製瀏覽器的按鈕和輸入框,網絡線程負責處理網絡堆棧以從互聯網接收數據,存儲線程控制對文件的訪問等。 當在地址欄中鍵入URL時,你的輸入將由瀏覽器進程的UI線程處理。緩存

clipboard.png
圖1:頂部的瀏覽器UI,底部有UI,網絡和存儲線程的瀏覽器進程圖安全

一個簡單的導航過程

第1步:處理輸入

當用戶開始輸入地址欄時,UI線程首先要判斷的是「這是搜索查詢仍是URL?」。 由於在Chrome中,地址欄也是搜索輸入框,所以UI線程須要解析並判斷是將你的輸入發送到搜索引擎仍是去請求對應的網站。服務器

clipboard.png
圖1:UI線程詢問輸入是搜索查詢仍是URL微信

第2步:開始導航

當用戶敲回車時,UI線程啓動網絡調用以獲取站點內容。 加載指示圖標顯示在選項卡的一角,網絡線程使用適當的協議,如DNS解析和爲請求創建TLS鏈接。網絡

clipboard.png
圖2:UI線程與網絡線程進行通訊以導航到mysite.com多線程

此時,網絡線程能夠接收像HTTP 301那樣的服務器重定向頭。在這種狀況下,網絡線程會通知UI線程服務器正在請求重定向。以後會啓動另外一個URL請求。架構

第3步:讀取響應

一旦響應主體(有效負載)開始進入,網絡線程會在必要時查看流的前幾個字節。 響應中的Content-Type頭應該說明它是什麼類型的數據,但因爲它可能丟失或發生錯誤,因此在這裏完成MIME類型嗅探。 這在源代碼的註釋中被稱爲「棘手的事情」。 你能夠閱讀這些註釋,來了解不一樣的瀏覽器是如何處理內容類型與有效載荷的。

clipboard.png
圖3:包含Content-Type和有效負載的響應頭,它是實際數據

若是響應是HTML文件,那麼下一步就是將數據傳遞給渲染器進程,但若是它是zip文件或其餘文件,則表示它是一個下載請求,所以須要將數據傳遞給 下載管理器。

clipboard.png
圖4:網絡線程詢問響應數據是否來自安全站點的HTML

這也是進行 SafeBrowsing檢查的地方。 若是域和響應數據彷佛與已知的惡意站點匹配,則網絡線程會發出警告以顯示警告頁面。 此外,發生跨源讀取阻止(CORB)檢查是爲了確保敏感的跨站數據不會進入渲染器進程。

第3步:查找渲染器進程

完成全部檢查而且網絡線程確信瀏覽器應該導航到所請求的站點後,網絡線程會告知UI線程數據已準備就緒。 而後UI線程找到渲染器進程以進行網頁的渲染。

clipboard.png
圖5:網絡線程告訴UI線程找到渲染進程

因爲網絡請求可能須要幾百毫秒才能獲得響應,因此在這裏進行了加速此過程的優化。 當UI線程在第2步向網絡線程發送URL請求時,它已經知道他們正在導航到哪一個站點。 UI線程嘗試與網絡請求並行地主動查找或啓動渲染器進程。 若是一切按預期進行,當網絡線程接收數據時,渲染器進程已處於備用狀態。 若是導航重定向跨站點,則可能不會使用此備用進程,在這種狀況下可能須要不一樣的進程。

第4步:提交導航

如今數據和渲染器進程已準備就緒,IPC將把導航從瀏覽器進程發送到渲染器進程以進行提交。它同時還傳遞數據流,所以渲染器進程能夠繼續接收HTML數據。 一旦瀏覽器進確認已經提交到了渲染器進程中,導航就完成了,文檔加載階段就開始了。

此時,地址欄會更新,安全指示器和站點設置UI會反映新頁面的站點信息。 選項卡的會話歷史記錄將更新,所以後退/前進按鈕將能夠逐步瀏覽剛導航到的站點。爲了便於在關閉選項卡或窗口時可以對選項卡/會話進行還原,會話的歷史記錄將被存儲在磁盤上。

clipboard.png
圖6:瀏覽器和渲染器進程之間的IPC,請求呈現頁面

額外步驟:初始加載完成

提交導航後,渲染器進程繼續加載資源並呈現頁面。 咱們將會在下一篇文章中詳細介紹這一階段的詳情。 一旦渲染器進程「完成」渲染,它就會將一個IPC發送回瀏覽器進程(這發生在全部onload事件觸發了頁面中的全部幀並完成執行以後)。 此時,UI線程會中止選項卡上的加載指示器。

儘管已經「完成」,不過客戶端 JavaScript 仍然能夠加載額外的資源並在此以後呈現新的視圖。

clipboard.png
圖7:渲染器進程經過IPC通知瀏覽器進程頁面已「加載完成」

導航到其餘站點

簡單的導航完成了! 可是若是用戶再次將不一樣的URL放到地址欄會發生什麼? 好吧,瀏覽器進程會經過相同的步驟導航到不一樣的站點。 但在它在作到這一點以前,還須要檢查當前正在渲染的站點,若是他們關心beforeunload事件的話。

當你嘗試從新導航或關閉選項卡時,beforeunload能夠建立「要離開這個網站嗎?」 警告。 因爲選項卡內包含JavaScript代碼的全部內容都由渲染器進程處理,所以瀏覽器進程必須在進行新導航請求時檢查當前渲染器進程。

警告:不要添加無條件的 beforeunload處理程序。 由於它會產生更多延遲,甚至在啓動導航以前須要執行一些處理。 應該僅在須要時添加此事件處理,例如,若是須要警告用戶他們可能會丟失在頁面上輸入的數據時。

clipboard.png
圖8:瀏覽器進程經過IPC通知渲染器進程它將要導航到另外一個站點

若是導航是從渲染器進程啓動的(例如用戶單擊連接或客戶端JavaScript執行window.location ="https://newsite.com"),那麼渲染器進程會首先檢查beforeunload處理。 而後,它經歷與瀏覽器進程啓動導航相同的過程。 惟一的區別是導航請求從渲染器進程發送到瀏覽器進程。

當新導航進入的站點與當前渲染的站點不一樣時,將會調用另外一個單獨的渲染進程來處理新導航,同時保持當前渲染進程以處理unload等事件。 有關更多信息,請參閱頁面生命週期狀態概述以及如何使用 頁面生命週期 API 掛鉤事件。

clipboard.png
圖9:從瀏覽器進程到新渲染器進程的2個IPC,通知新渲染器渲染頁面並通知舊渲染器進程卸載

若是是Service Worker

最近對該導航過程的一個改變是引入了service worker。 service worker是一種在應用代碼中編寫網絡代理的方法;它容許Web開發人員更好地控制本地緩存內容以及什麼時候從網絡獲取新數據。 若是將service worker設置爲從緩存加載頁面,則無需從網絡請求數據。

要記住的重要一點是Service Worker是在渲染器進程中運行的JavaScript代碼。 可是當導航請求到來時,瀏覽器進程怎麼才能知道該站點有Service Worker?

clipboard.png
圖10:瀏覽器進程中的網絡線程查找Service Worker範圍

註冊Service Worker時,將保留Service Worker的範圍做爲參考(你能夠在「Service Worker生命週期」一文中閱讀有關範圍的更多信息)。 當導航發生時,網絡線程根據註冊的Service Worker範圍檢查域,若是爲該URL註冊了Service Worker,則UI線程找到渲染器進程來執行Service Worker代碼。 Service Worker能夠從緩存加載數據,無需從網絡請求數據,也能夠從網絡請求新資源。

clipboard.png
圖11:瀏覽器進程中的UI線程啓動渲染器進程以處理Service Worker; 而後,渲染器進程中的工做線程從網絡請求數據

導航預加載

能夠看到,若是Service Worker最終決定從網絡請求數據,則瀏覽器進程和渲染器進程之間的往返通訊可能會致使延遲。 導航預加載是一種經過與Service Worker並行加載資源來加速此過程的機制。 它用header標記這些請求,容許服務器爲這些請求發送不一樣的內容,例如:只更新部分數據而不是整個文檔。

clipboard.png
圖12:瀏覽器進程中的UI線程啓動渲染器進程,在並行啓動網絡請求的同時處理Service Worker

總結

在本文中,咱們研究了導航過程當中發生的事情,以及響應頭和客戶端JavaScript等Web應用代碼是如何與瀏覽器交互的。 瞭解瀏覽器經過網絡獲取數據的步驟,能夠更容易地理解爲何開發導航預加載等API。 在下一篇文章中,咱們將深刻探討瀏覽器如何處理HTML/ CSS/JavaScript來呈現頁面。


本文首發微信公衆號:jingchengyideng
點擊下面連接查看其它章節文章

相關文章
相關標籤/搜索