在前端面試中,有一道經典的面試題:請描述一下從url輸入到頁面渲染的過程。這道題很考察候選人的能力和知識深度, 今天咱們以這個問題爲基礎,講一下在此過程當中能作哪些優化。css
首先作 DNS 查詢,若是這一步作了智能 DNS 解析的話,會提供訪問速度最快的 IP 地址回來html
接下來是 TCP 握手,應用層會下發數據給傳輸層,這裏 TCP 協議會指明兩端的端口號,而後下發給網絡層。網絡層中的 IP 協議會肯定 IP 地址,而且指示了數據傳輸中如何跳轉路由器。而後包會再被封裝到數據鏈路層的數據幀結構中,最後就是物理層面的傳輸了前端
TCP 握手結束後會進行 TLS 握手,而後就開始正式的傳輸數據面試
數據在進入服務端以前,可能還會先通過負責負載均衡的服務器,它的做用就是將請求合理的分發到多臺服務器上,這時假設服務端會響應一個 HTML 文件後端
首先瀏覽器會判斷狀態碼是什麼,若是是 200 那就繼續解析,若是 400 或 500 的話就會報錯,若是 300 的話會進行重定向,這裏會有個重定向計數器,避免過屢次的重定向,超過次數也會報錯瀏覽器
瀏覽器開始解析文件,若是是 gzip 格式的話會先解壓一下,而後經過文件的編碼格式知道該如何去解碼文件緩存
文件解碼成功後會正式開始渲染流程,先會根據 HTML 構建 DOM 樹,有 CSS 的話會去構建 CSSOM 樹。若是遇到 script 標籤的話,會判斷是否存在 async 或者 defer ,前者會並行進行下載並執行 JS,後者會先下載文件,而後等待 HTML 解析完成後順序執行,若是以上都沒有,就會阻塞住渲染流程直到 JS 執行完畢。遇到文件下載的會去下載文件,這裏若是使用 HTTP 2.0 協議的話會極大的提升多圖的下載效率。安全
初始的 HTML 被徹底加載和解析後會觸發 DOMContentLoaded 事件服務器
CSSOM 樹和 DOM 樹構建完成後會開始生成 Render 樹,這一步就是肯定頁面元素的佈局、樣式等等諸多方面的東西網絡
在生成 Render 樹的過程當中,瀏覽器就開始調用 GPU 繪製,合成圖層,將內容顯示在屏幕上了
http是超文本傳輸協議,可是在信息傳輸過程當中,因爲通訊使用的是明文,可能存在信息被竊取和篡改的問題。
可使用安全的https替代http
詳見Carlo大佬的博文 細說https
當發送http請求時,瀏覽器首先會按順序檢查如下四項是否存在緩存
MemoryCache,是指存在內存中的緩存。從優先級上來講,它是瀏覽器最早嘗試去命中的一種緩存。從效率上來講,它是響應速度最快的一種緩存。瀏覽器秉承的是「節約原則」,咱們發現,Base64 格式的圖片,幾乎永遠能夠被塞進 memory cache,這能夠視做瀏覽器爲節省渲染開銷的「自保行爲」;此外,體積不大的 JS、CSS 文件,也有較大地被寫入內存的概率——相比之下,較大的 JS、CSS 文件就沒有這個待遇了,內存資源是有限的,它們每每被直接甩進磁盤。
Service Worker 是一種獨立於主線程以外的 Javascript 線程。它脫離於瀏覽器窗體,所以沒法直接訪問 DOM。這樣獨立的個性使得 Service Worker 的「我的行爲」沒法干擾頁面的性能,這個「幕後工做者」能夠幫咱們實現離線緩存、消息推送和網絡代理等功能。咱們藉助 Service worker 實現的離線緩存就稱爲 Service Worker Cache。
它又分爲強緩存和協商緩存。優先級較高的是強緩存,在命中強緩存失敗的狀況下,纔會走協商緩存。
Push Cache 是指 HTTP2 在 server push 階段存在的緩存。
關於瀏覽器的強緩存和協商緩存,詳見Carry的博文 前端靜態資源緩存
關於sevice Worker緩存, 詳見Carry的博文 前端靜態資源緩存之sevice worker
CDN 的核心點有兩個,一個是緩存,一個是回源。
「緩存」就是說咱們把資源 copy 一份到 CDN 服務器上這個過程,「回源」就是說 CDN 發現本身沒有這個資源(通常是緩存的數據過時了),轉頭向根服務器(或者它的上層服務器)去要這個資源的過程。
CDN 每每被用來存放靜態資源。所謂「靜態資源」,就是像 JS、CSS、圖片等不須要業務服務器進行計算即得的資源。而「動態資源」,顧名思義是須要後端實時動態生成的資源,較爲常見的就是 JSP、ASP 或者依賴服務端渲染獲得的 HTML 頁面。
那「非純靜態資源」呢?它是指須要服務器在頁面以外做額外計算的 HTML 頁面。具體來講,當我打開某一網站以前,該網站須要經過權限認證等一系列手段確認個人身份、進而決定是否要把 HTML 頁面呈現給我。這種狀況下 HTML 確實是靜態的,但它和業務服務器的操做耦合,咱們把它丟到CDN 上顯然是不合適的。
另外,CDN的域名必須和主業務服務器的域名不同,要不,同一個域名下面的Cookie各處跑,浪費了性能流量的開銷,CDN域名放在不一樣的域名下,能夠完美地避免了沒必要要的 Cookie 的出現!
瀏覽器的渲染機制通常分爲如下幾個步驟:
在渲染dom的時候,瀏覽器實際上所作的工做是
CSS 是阻塞的資源。瀏覽器在構建 CSSOM 的過程當中,不會渲染任何已處理的內容。即使 DOM 已經解析完畢了,只要 CSSOM 不 OK,那麼渲染這個事情就不 OK。咱們將 CSS 放在 head 標籤裏 和儘快 啓用 CDN 實現靜態資源加載速度的優化。 CSS 選擇符是從右到左進行匹配的,好比 #myList li {}實際開銷至關高。
JS 引擎是獨立於渲染引擎存在的。咱們的 JS 代碼在文檔的何處插入,就在何處執行。當 HTML 解析器遇到一個 script 標籤時,它會暫停渲染過程,將控制權交給 JS 引擎。
JS 引擎對內聯的 JS 代碼會直接執行,對外部 JS 文件還要先獲取到腳本、再進行執行。等 JS 引擎運行完畢,瀏覽器又會把控制權還給渲染引擎,繼續 CSSOM 和 DOM 的構建。
咱們將耗時的js操做放在頁面的尾部,等待html和css渲染完畢再執行js防止js阻塞頁面渲染。
JS中分爲同步任務和異步任務,同步任務在執行棧中執行,異步任務的回調被放在任務隊列中,等待執行棧空閒時執行。 setTimeout/setInterval,XHR/fetch的回調函數都屬於異步任務。
任務棧執行一次的過程屬於一次宏任務,在一個宏任務執行結果後,在下一個宏任務執行前,GUI渲染線程開始工做,對頁面進行渲染。
微任務是在一次宏任務執行完畢以後,GUI線程執行以前執行的任務。當宏任務執行完,會在渲染前,將執行期間所產生的全部微任務都執行完. Promise,process.nextTick等,屬於微任務
合理的安排宏任務微任務以及dom操做的順序,能夠儘量的減小無效的dom操做。
更多關於js和Event Loop的知識,請參考雲中橋大佬的博文 從多線程到Event Loop全面梳理
迴流:當咱們對 DOM 的修改引起了 DOM 幾何尺寸的變化(好比修改元素的寬、高或隱藏元素等)時,瀏覽器須要從新計算元素的幾何屬性(其餘元素的幾何屬性和位置也會所以受到影響),而後再將計算的結果繪製出來。這個過程就是迴流(也叫重排)。
重繪:當咱們對 DOM 的修改致使了樣式的變化、卻並未影響其幾何屬性(好比修改了顏色或背景色)時,瀏覽器不需從新計算元素的幾何屬性、直接爲該元素繪製新的樣式(跳過了上圖所示的迴流環節)。這個過程叫作重繪。
重繪不必定致使迴流,迴流必定會致使重繪。迴流比重繪作的事情更多,帶來的開銷也更大。在開發中,要從代碼層面出發,儘量把迴流和重繪的次數最小化。
負載均衡: session複製