深刻了解現代web瀏覽器(二) -- 導航

導航欄發生了什麼?

這是介紹Chrome內部工做博客系列的第2部分。在上一篇博客中,咱們學習了不一樣的進程和線程去處理瀏覽器的不一樣部分。在這篇文章,咱們深刻去了解爲了展現一個網頁每一個進程和線程是如何通訊的。javascript

咱們看一下web瀏覽器的一個簡單示例:當你在瀏覽器中輸入一個url,瀏覽器從網絡獲取數據而且顯示一個頁面。在本文中,咱們將重點介紹用戶請求站點和瀏覽器準備渲染一個頁面(也稱之爲導航)。java

從瀏覽器進程開始

正如咱們在第一部分中介紹的CPU、GPU和多進程架構,選項卡以外的全部內容都是瀏覽器進程處理的。瀏覽器進程具備線程,例如用於繪製按鈕和輸入部分的UI線程,用於處理網絡堆棧和從網絡獲取數據的網絡線程,用於控制訪問文件的存儲線程。在地址欄中輸入URL,你的輸入將由瀏覽器進程的UI線程處理。web

browserprocesses.png

簡單的導航

步驟1:處理輸入

當一個用戶開始在地址欄中輸入內容,UI線程首先問「這是搜索仍是一個URL?」。在Chrome中,地址欄也是一個搜索輸入區域,所以UI線程須要解析而且決定將內容發送給搜索引擎,仍是你請求的網站。api

input.png

步驟2:開始導航

當用戶按下Enter鍵,UI線程會開始調用網絡請求去獲取站點內容。在選項卡的角上顯示loading旋轉,網絡線程經過相應的協議,例如DNS查找,爲請求創建TLS鏈接。瀏覽器

navstart.png
此時,網絡線程可能會收到服務器的重定向頭好比http 301。在這種狀況下,網絡線程與UI線程開始通訊,服務器請求重定向。而後,會啓動另外一個URL請求。緩存

步驟3:讀取響應

一旦響應體開始回來,網絡進程將在必要的時候查看流的前幾個字節。響應的Content-Type頭會說明是哪一種數據類型,可是可能會丟失或者錯誤,MIME Type嗅探會在這裏完成。就像源碼中描述的同樣這是一個「棘手的業務」。你能夠閱讀註釋去了解不一樣瀏覽器如何處理content-type/payload對。安全

MIME Type嗅探MDN解釋:
在缺失 MIME 類型或客戶端認爲文件設置了錯誤的 MIME 類型時,瀏覽器可能會經過查看資源來進行MIME嗅探。每個瀏覽器在不一樣的狀況下會執行不一樣的操做。由於這個操做會有一些安全問題,有的 MIME 類型表示可執行內容而有些是不可執行內容。瀏覽器能夠經過請求頭  Content-Type 來設置  X-Content-Type-Options 以阻止MIME嗅探。

若是響應是一個HTML文件,那麼下一步須要將數據傳遞到渲染進程,可是若是是zip文件或者其餘文件,則意味着這是一個下載請求,所以須要將數據傳遞到下載管理器。服務器

sniff.png
也是在這裏進行安全瀏覽檢查。若是域名和響應數據與已知的惡意站點匹配,那麼網絡進程會彈出一個警告去顯示一個警告頁。此外,Cross Origin Read Blocking(CORB)觸發是爲了確保敏感站點數據不傳遞給渲染進程。網絡

在谷歌的官網是這麼解釋的:
Cross-Origin Read Blocking (CORB) is an algorithm that can identify and block dubious cross-origin resource loads in web browsers before they reach the web page. CORB reduces the risk of leaking sensitive data by keeping it further from cross-origin web pages. In most browsers, it keeps such data out of untrusted script execution contexts. In browsers with Site Isolation, it can keep such data out of untrusted renderer processes entirely, helping even against side channel attacks like Spectre.

步驟4:查找渲染進程

當全部的檢查都完成,而且網絡線程確認導航到請求的站點,網絡線程就會通知UI線程數據準備好了。UI線程就會查找一個渲染進程負責渲染web頁面。
findrenderer.png
因爲網絡強求須要花費數百毫秒才能獲得響應,所以有一個優化用來加快此進程。當UI線程在第2步發送一個URL請求給網絡線程的時候,它一句知道了須要導航到的站點是哪一個。UI線程主動地嘗試查找,而且啓動一個與網絡請求並行的渲染進程。這樣,若是一切符合預期,當一個網絡進程接收到數據的時候,渲染進程已經處於準備好的狀態。若是導航重定向跨站點那麼該準備好的進程就沒法使用,在這種狀況下,可能須要另一個進程。架構

步驟5:提交導航

如今數據和渲染進程都已經準備好,從瀏覽器進程往渲染進程發送一個IPC用於提交導航。它也會傳遞數據流,所以渲染進程能夠不斷接收HTML數據。一旦瀏覽器進程收到確認提交在渲染進程發生,導航完成而且文檔加載階段開始。

此時,地址欄會更新,安全指示和站點設置UI將會反應出新頁面的站點信息。選項卡的會話歷史將會engine,所以「前進/後退」按鈕將會單步瀏覽剛剛導航的站點。爲了便於恢復,你關閉的一個選項卡或者窗口,會話歷史會被存儲在硬盤上。
commit.png

額外步驟:初始化記載完成

導航提交後,渲染進程將繼續加載資源而且渲染頁面。咱們將在下一篇文章中詳細介紹在這個階段發生了什麼。當渲染進程「完成」渲染,它會將一個IPC發送回瀏覽器進程(這裏是當頁面全部frame的onload事件觸發而且執行完成)。此時,UI進程將中止在選項卡上加載loading旋轉。

我說的「完成」,由於在此時客戶端Javscript能夠繼續加載額外的資源,而且渲染新的視圖。

loaded.png

導航到其餘站點

簡單的導航完成了!可是若是一個用戶再次在地址欄輸入了另外的URL會發生什麼?固然,瀏覽器進程要通過相同的步驟導航到另外的站點。但在此以前,它須要檢查當前渲染的站點,若是它們有 beforeunload 的相關事件。

當你嘗試離開或者關閉選項卡的時候, beforeunload 能夠建立「離開此站點嗎」的警告。選項卡中的全部內容包含Javascript代碼都是渲染進程處理的,所以當一個新的導航請求進來時,瀏覽器進程必須檢查當前的渲染進程。

⚠️ 警告:不要添加無條件的 beforeunload 處理。由於須要在導航前執行處理程序,由於建立了更多的延遲。這個事件處理僅僅在須要的時候再去添加,例如須要警告用戶可能會丟失她們在頁面上輸入的數據。
beforeunload.png

若是導航是從渲染進程啓動的(例如用戶點擊了一個連接或者客戶端javascript運行了 window.location = "https://newsite.com"),渲染進程會首先檢查 beforeunload 處理程序。而後,它將會通過與瀏覽器進程啓動導航的相同步驟。惟一的區別就是導航請求從渲染進程到瀏覽器進程啓動。

當新導航到一個與當前渲染的不一樣站點時,將會調用一個獨立的渲染進程去處理新的導航,當前的渲染進程會繼續處理像 unload 之類的事件。更多信息能夠查看 頁面生命週期轉檯概述,以及如何使用 頁面生命週期API

unload.png

Service Worker 的狀況下

這種導航進程的最近更新是引入了Service Worker。Service Worker是在你的應用程序中編寫網絡代理的一種方式;容許web開發者更好地控制本地緩存數據和何時從網絡獲取新數據。若是 Service Worker 設置從緩存中讀取頁面,則無需從網絡去請求數據。

須要記住的最重要的部分是 Service Worker 是運行在渲染進程的 Javascript 代碼。可是當導航請求進入的時候,可是瀏覽器進程如何知道站點是否有 Service Worker?

當一個 Service Worker 註冊後,Service Worker的做用域會保留一個引用(你能夠在Service Worker 生命週期的文章中閱讀到更多信息)。當導航開始的時候,網絡線程去檢查域名是否註冊了 Service Worker,若是爲一個url註冊了Service Worker,UI進程會查找渲染進程去執行Service Worker代碼。Service Worker能夠從緩存中加載數據,無需從網絡中請求數據,或者也能夠從網絡中請求新的資源。

serviceworker.png

導航預加載

若是Service Worker最終決定從網絡請求數據,那麼能夠看到在瀏覽器進程和渲染進程之間的往返會形成延遲。導航預加載 是一種經過Service Worker啓動的同時並行加載資源來加快這個過程的機制。它使用標記頭標記這些請求,使服務器爲這些請求發送不一樣的內容,例如,只更新數據而不是整個文檔。

navpreload.png

總結

在這篇文章中,咱們學習了導航期間發生了什麼,web應用程序好比響應頭和客戶端Javascript與瀏覽器是如何交互的。瞭解瀏覽器從網絡獲取數據須要經歷的步驟,使得理解爲何開發了例如導航預加載這樣的API。在下一篇文章中,咱們將深刻探討瀏覽器如何評估咱們的HTML/CSS/JavaScript去渲染頁面。

相關文章
相關標籤/搜索