最近發現國外有一個系列,專門探究從輸入URL到頁面可交互的詳細過程,是一份乾貨十足的好資料。筆者決定分爲四篇文章對其進行有刪減地翻譯,只但願能對你們有所幫助,畢竟這是前端必備的知識點,也是容易忽略掉某些細節的知識點。事先聲明,這個系列徹底由筆者手翻,若有翻譯不當的地方,懇請讀者給出改進意見!數據庫
接下來開始第一篇——《從服務端到客戶端》跨域
在瀏覽器執行任何工做以前,它須要先知道訪問的是哪裏。有幾種方法能夠實現訪問:在地址欄中輸入URL、點擊(或觸碰)一個頁面上或其餘app中的超連接、或者點擊你的收藏。不管是哪一種狀況,都會觸發一個動做——導航。導航永遠是網頁中交互的第一步,由於它觸發了以下一系列事件的連鎖反應直至網頁被加載。瀏覽器
一旦URL被提供給瀏覽器去加載,如下這些事情就會悄悄在背後發生:緩存
首先,瀏覽器須要判斷這個URL是否明確爲HTTP(不安全)協議。若是它是一個HTTP的請求,那麼瀏覽器則須要檢查這個域名是否在HSTS的清單中(HTTP Strict Transport Security——嚴格安全傳輸)。這個清單包含了一個預加載好的名單以及你以前訪問過的使用HSTS的網站名單,它們都是存放在瀏覽器中的。若是你請求的HTTP開頭的host處於在HSTS清單中,那這個請求會被強制轉爲HTTPS開頭的URL而非HTTP。這就是爲何你會發現當你試圖在一個現代瀏覽器中輸入http://www.bing.com 會被轉爲https://www.bing.com。安全
接着,瀏覽器須要判斷service worker是否能夠用來處理請求——這對於那些離線的沒有網絡鏈接的用戶來講相當重要。Service workers相對來說是比較新的瀏覽器特性。它經過對網絡請求的攔截來提供離線應用的能力,這些請求均可以被保留在腳本控制的緩存中。這是頗有用的,由於它使網站可以更好地控制什麼時候使用緩存的項目。這些緩存是跟域名綁定的,這意味着每一個域均可以有本身的緩存黑盒,並與其餘域的緩存隔離開。服務器
當一個頁面被訪問時,能夠註冊一個Service worker,這個動做是由一個工做線程來完成的,它能夠把service worker的註冊和URL映射記錄在本地數據庫中。要判斷一個service worker是否被安裝,只需在這個本地數據中查找是否有對應的URL。若是爲service worker查到了對應的URL,它就會被容許處理請求的迴應。而若是瀏覽器支持Navigation Preload的新特性,且開發者使用了它,那麼瀏覽器會同時去發起首次導航請求。這是有好處的,由於它避免了瀏覽器由於service worker啓動過慢而對頁面渲染的影響。微信
當瀏覽器發現沒有service worker來處理初始化請求時,就會繼續網絡請求層。網絡
瀏覽器會經過網絡請求層檢查緩存中是否存在全新的響應。這常常是由響應頭中的Cache-Control字段決定的,字段中設置的max-age值能夠決定緩存多久會刷新,而no-store字段能夠代表是否應該被緩存。可想而知,若是瀏覽器在緩存中找不到任何東西,那麼就須要進行網絡請求了。而若是在緩存中有一個全新的響應,它就會被當即返回以用於頁面加載。若是存在一個不夠「新」的資源,那麼瀏覽器會把這個請求轉爲一個附帶條件的校驗請求,也就是請求頭帶上If-Modified-Since或者If-None-Match去告訴服務端當前瀏覽器存的是哪一個版本的緩存。服務端則能夠返回HTTP 304狀態碼(沒有更改)告訴瀏覽器這個緩存是最新的,不帶響應正文;或者返回HTTP 200狀態碼告訴瀏覽器這個緩存資源已通過期了,並直接返回最新的資源app
若是如今有一個和主機、端口創建起鏈接的請求,那麼它會被瀏覽器複用而不是從新去創建一個,不然,瀏覽器會走網絡層以瞭解是否須要執行DNS(域名系統)查詢。這個動做的具體流程是,先尋找本地的DNS緩存(存儲在你的設備上),而後根據DNS緩存是否過時來決定是否訪問遠程域名服務器(它們由互聯網服務提供商ISP分配主機地址),域名服務器最終會返回準確的IP地址給瀏覽器進行鏈接。
某些狀況下,瀏覽器可以預先知道哪些域名會被訪問,從而先準備好對這些域名的鏈接。一個網頁能夠經過在link標籤中使用資源提示(resource hints),好比rel="preconnect" 來提示瀏覽器提早準備好鏈接。在以下場景中,資源提示是頗有用的,好比一個用戶在必應的搜索結果頁,而一般的預期中,前幾條搜索結果是最有可能被用戶訪問的。此時,提早準備好對那些域名的鏈接能夠在那些網頁被點擊以後節省掉DNS查詢和域名鏈接的消耗。
瀏覽器如今能夠與服務器創建起鏈接了,且服務端知道本身須要從客戶端接收和發送消息了。若是咱們是使用TLS,咱們須要執行一次TLS握手流程以驗證服務器提供的證書。
第一個經過這個鏈接發起的請求叫作頂級頁面請求。一般狀況,這個請求的資源會是一個HTLML文件,從服務器返回到客戶端
當響應以數據流的形式到達客戶端後,客戶端就開始進行解析了。首先,瀏覽器會檢查響應頭。HTTP頭部是以鍵值對的形式做爲HTTP響應的一部分。若是響應頭指示要進行重定向(好比,經過Location字段),瀏覽器就會再一次進行導航並回到最初的那一步,檢查是否須要執行HSTS的升級(爲HTTPS)。
若是服務器的響應數據被壓縮或分塊了,瀏覽器會嘗試對它進行解壓和合並。
待響應被解讀完成後,瀏覽器還會並行地將其寫入網絡緩存中。
接着,瀏覽器會搞清發送過來的文件的MIME類型,這樣它才能以適當的方式去加載這份文件。好比,一份圖片文件會原封不動地被加載進來,但HTML文件則會被執行解析和渲染。若是HTML解析器被調用了,那麼它會掃描出那些可能要下載的資源文件的URL,以便瀏覽器在頁面渲染以前就能夠開始去下載。這一部分的更多細節會在系列文章的下一篇中具體展開。
截至目前,被請求的導航URL已經輸入到了瀏覽器的歷史中,這樣它就能夠被用於瀏覽器導航的前進和後退功能了。
這裏有一張更詳細的流程圖,它可讓你對目前討論的內容有個整體的概覽:
如你所知的,頁面會繼續發起請求,由於頁面上還有不少對總體體驗很重要的子資源,好比圖片,腳本,和樣式表。另外,這些子資源中引用到的其餘資源,好比背景圖片(CSS中引用的),或者其餘由fetch(),import(),AJAX請求發起的資源。若是沒有這些的話,咱們將只能看到一個原始的無交互的空頁面。
剛剛已經提到,瀏覽器會管理網絡緩存,以便在多種場景下能對下載好的資源的重複利用。這對那些長久不更新的資源尤爲有用,好比logo和第三方的腳本文件。咱們應該儘量地利用好這些緩存,由於這有利於減小對外的網絡請求數,取而代之的是本地的可複用的緩存資源。
響應頭中的Cache-Control字段控制着瀏覽器的緩存邏輯。某些狀況下,你能夠謹慎地告訴瀏覽器徹底不要進行緩存,好比使用Cache-Control: no-store,由於這個資源在預期中是一直在變化的。另外一種狀況下,當給定URL的響應內容永遠不會變化時,咱們能夠設置Cache-Control: immutable以便瀏覽器能夠永遠地緩存它。實際應用中,當咱們使用不一樣的URL來指向不一樣版本的同一份資源時,咱們就能夠採用這種作法,而非對同一個URL的資源進行更改,由於被緩存的版本會一直被使用且不會去發送請求。
Origin是由協議,主機名和端口共同組成的。例如,www.bing.com:443 這個origin是由https的協議, www.bing.com 的主機名和443的端口組成的。只要其中任何一個部分有差別,那麼在二者進行比較時,都會被認爲是不一樣源的。好比https://images.bing.com:443 和 www.bing.com:80 就是不一樣源的。
Origin對於瀏覽器來講是很重要的概念,由於它定義了數據是如何被隔離和保護的。大多數狀況,爲了安全考慮,瀏覽器會強制使用同源策略,意味着一個源沒法訪問另外一個源的數據。就像上面提到的兩個源——images.bing.com:443 和 www.bing.com:80 ,它們互相都沒法訪問對方的緩存(service worker的)。
若是bing.com想要從microsoft.com加載一個Javascript文件,它就須要在實行同源策略的瀏覽中發起一個跨域資源請求。想要容許這種操做的話,microsoft.com就須要與bing.com經過指定CORS(跨域資源共享)的頭部進行合做。
既然你已經明白了資源如何從服務器走到客戶端以及之間的全部細節,那麼請繼續關注網頁加載的下一步:從HTML標籤轉爲DOM。