原文地址:https://developers.google.com/web/updates/2018/09/inside-browser-part2
導航欄發(fā)生了什么殴泰?
這是介紹Chrome內部工作博客系列的第2部分契讲。在上一篇博客中钦铁,我們學習了不同的進程和線程去處理瀏覽器的不同部分。在這篇文章表牢,我們深入去了解為了展示一個網頁每個進程和線程是如何通信的瓷患。
我們看一下web瀏覽器的一個簡單示例:當你在瀏覽器中輸入一個url,瀏覽器從網絡獲取數(shù)據(jù)并且顯示一個頁面臂拓。在本文中传蹈,我們將重點介紹用戶請求站點和瀏覽器準備渲染一個頁面(也稱之為導航)押逼。
從瀏覽器進程開始
正如我們在第一部分中介紹的CPU步藕、GPU和多進程架構,選項卡之外的所有內容都是瀏覽器進程處理的挑格。瀏覽器進程具有線程咙冗,例如用于繪制按鈕和輸入部分的UI線程,用于處理網絡堆棧和從網絡獲取數(shù)據(jù)的網絡線程漂彤,用于控制訪問文件的存儲線程雾消。在地址欄中輸入URL,你的輸入將由瀏覽器進程的UI線程處理挫望。
簡單的導航
步驟1:處理輸入
當一個用戶開始在地址欄中輸入內容立润,UI線程首先問“這是搜索還是一個URL?”。在Chrome中媳板,地址欄也是一個搜索輸入?yún)^(qū)域范删,因此UI線程需要解析并且決定將內容發(fā)送給搜索引擎,還是你請求的網站拷肌。
步驟2:開始導航
當用戶按下Enter鍵,UI線程會開始調用網絡請求去獲取站點內容旨巷。在選項卡的角上顯示loading旋轉巨缘,網絡線程通過相應的協(xié)議,例如DNS查找采呐,為請求建立TLS連接若锁。
此時,網絡線程可能會收到服務器的重定向頭比如http 301斧吐。在這種情況下又固,網絡線程與UI線程開始通信,服務器請求重定向煤率。然后仰冠,會啟動另一個URL請求。
步驟3:讀取響應
一旦響應體開始回來蝶糯,網絡進程將在必要的時候查看流的前幾個字節(jié)洋只。響應的Content-Type頭會說明是哪種數(shù)據(jù)類型,但是可能會丟失或者錯誤昼捍,MIME Type嗅探會在這里完成识虚。就像源碼中描述的一樣這是一個“棘手的業(yè)務”。你可以閱讀注釋去了解不同瀏覽器如何處理content-type/payload對妒茬。
MIME Type嗅探MDN解釋:
在缺失 MIME 類型或客戶端認為文件設置了錯誤的 MIME 類型時担锤,瀏覽器可能會通過查看資源來進行MIME嗅探。每一個瀏覽器在不同的情況下會執(zhí)行不同的操作乍钻。因為這個操作會有一些安全問題肛循,有的 MIME 類型表示可執(zhí)行內容而有些是不可執(zhí)行內容铭腕。瀏覽器可以通過請求頭Content-Type
來設置X-Content-Type-Options
以阻止MIME嗅探。
如果響應是一個HTML文件育拨,那么下一步需要將數(shù)據(jù)傳遞到渲染進程谨履,但是如果是zip文件或者其他文件,則意味著這是一個下載請求熬丧,因此需要將數(shù)據(jù)傳遞到下載管理器笋粟。
也是在這里進行安全瀏覽檢查。如果域名和響應數(shù)據(jù)與已知的惡意站點匹配析蝴,那么網絡進程會彈出一個警告去顯示一個警告頁害捕。此外,Cross Origin Read Blocking(CORB)觸發(fā)是為了確保敏感站點數(shù)據(jù)不傳遞給渲染進程闷畸。
在谷歌的官網是這么解釋的:
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線程數(shù)據(jù)準備好了佑菩。UI線程就會查找一個渲染進程負責渲染web頁面盾沫。
由于網絡強求需要花費數(shù)百毫秒才能得到響應,因此有一個優(yōu)化用來加快此進程殿漠。當UI線程在第2步發(fā)送一個URL請求給網絡線程的時候赴精,它一句知道了需要導航到的站點是哪個。UI線程主動地嘗試查找绞幌,并且啟動一個與網絡請求并行的渲染進程蕾哟。這樣,如果一切符合預期莲蜘,當一個網絡進程接收到數(shù)據(jù)的時候谭确,渲染進程已經處于準備好的狀態(tài)。如果導航重定向跨站點那么該準備好的進程就無法使用票渠,在這種情況下逐哈,可能需要另外一個進程。
步驟5:提交導航
現(xiàn)在數(shù)據(jù)和渲染進程都已經準備好庄新,從瀏覽器進程往渲染進程發(fā)送一個IPC用于提交導航鞠眉。它也會傳遞數(shù)據(jù)流,因此渲染進程可以不斷接收HTML數(shù)據(jù)择诈。一旦瀏覽器進程收到確認提交在渲染進程發(fā)生械蹋,導航完成并且文檔加載階段開始。
此時羞芍,地址欄會更新哗戈,安全指示和站點設置UI將會反應出新頁面的站點信息。選項卡的會話歷史將會engine荷科,因此“前進/后退”按鈕將會單步瀏覽剛剛導航的站點唯咬。為了便于恢復纱注,你關閉的一個選項卡或者窗口,會話歷史會被存儲在硬盤上胆胰。
額外步驟:初始化記載完成
導航提交后狞贱,渲染進程將繼續(xù)加載資源并且渲染頁面。我們將在下一篇文章中詳細介紹在這個階段發(fā)生了什么蜀涨。當渲染進程“完成”渲染瞎嬉,它會將一個IPC發(fā)送回瀏覽器進程(這里是當頁面所有frame的onload事件觸發(fā)并且執(zhí)行完成)。此時厚柳,UI進程將停止在選項卡上加載loading旋轉氧枣。
我說的“完成”,因為在此時客戶端Javscript可以繼續(xù)加載額外的資源别垮,并且渲染新的視圖便监。
導航到其他站點
簡單的導航完成了!但是如果一個用戶再次在地址欄輸入了另外的URL會發(fā)生什么碳想?當然烧董,瀏覽器進程要經過相同的步驟導航到另外的站點。但在此之前胧奔,它需要檢查當前渲染的站點解藻,如果它們有 beforeunload 的相關事件。
當你嘗試離開或者關閉選項卡的時候葡盗,** beforeunload **可以創(chuàng)建“離開此站點嗎”的警告。選項卡中的所有內容包含Javascript代碼都是渲染進程處理的啡浊,因此當一個新的導航請求進來時觅够,瀏覽器進程必須檢查當前的渲染進程。
?? 警告:不要添加無條件的 **beforeunload **處理巷嚣。因為需要在導航前執(zhí)行處理程序喘先,因為創(chuàng)建了更多的延遲。這個事件處理僅僅在需要的時候再去添加廷粒,例如需要警告用戶可能會丟失她們在頁面上輸入的數(shù)據(jù)窘拯。
如果導航是從渲染進程啟動的(例如用戶點擊了一個鏈接或者客戶端javascript運行了 window.location = "https://newsite.com"),渲染進程會首先檢查 **beforeunload **處理程序坝茎。然后涤姊,它將會經過與瀏覽器進程啟動導航的相同步驟。唯一的區(qū)別就是導航請求從渲染進程到瀏覽器進程啟動嗤放。
當新導航到一個與當前渲染的不同站點時思喊,將會調用一個獨立的渲染進程去處理新的導航,當前的渲染進程會繼續(xù)處理像 **unload **之類的事件次酌。更多信息可以查看 頁面生命周期轉臺概述恨课,以及如何使用 頁面生命周期API 舆乔。
Service Worker 的情況下
這種導航進程的最近更新是引入了Service Worker。Service Worker是在你的應用程序中編寫網絡代理的一種方式剂公;允許web開發(fā)者更好地控制本地緩存數(shù)據(jù)和什么時候從網絡獲取新數(shù)據(jù)希俩。如果 Service Worker 設置從緩存中讀取頁面,則無需從網絡去請求數(shù)據(jù)纲辽。
需要記住的最重要的部分是 Service Worker 是運行在渲染進程的 Javascript 代碼颜武。但是當導航請求進入的時候,但是瀏覽器進程如何知道站點是否有 Service Worker文兑?
當一個 Service Worker 注冊后盒刚,Service Worker的作用域會保留一個引用(你可以在Service Worker 生命周期的文章中閱讀到更多信息)。當導航開始的時候绿贞,網絡線程去檢查域名是否注冊了 Service Worker因块,如果為一個url注冊了Service Worker,UI進程會查找渲染進程去執(zhí)行Service Worker代碼籍铁。Service Worker可以從緩存中加載數(shù)據(jù)涡上,無需從網絡中請求數(shù)據(jù),或者也可以從網絡中請求新的資源拒名。
導航預加載
如果Service Worker最終決定從網絡請求數(shù)據(jù)吩愧,那么可以看到在瀏覽器進程和渲染進程之間的往返會造成延遲。導航預加載 是一種通過Service Worker啟動的同時并行加載資源來加快這個過程的機制增显。它使用標記頭標記這些請求且改,使服務器為這些請求發(fā)送不同的內容,例如包蓝,只更新數(shù)據(jù)而不是整個文檔厕隧。
總結
在這篇文章中,我們學習了導航期間發(fā)生了什么炸站,web應用程序比如響應頭和客戶端Javascript與瀏覽器是如何交互的星澳。了解瀏覽器從網絡獲取數(shù)據(jù)需要經歷的步驟,使得理解為什么開發(fā)了例如導航預加載這樣的API旱易。在下一篇文章中禁偎,我們將深入探討瀏覽器如何評估我們的HTML/CSS/JavaScript去渲染頁面。