爲何輸入URL就能夠顯示想要的頁面?
輸入URL後瀏覽器作了些什麼?
前端能夠針對這些作哪些優化?javascript
瀏覽器的主要功能是將用戶選擇的web資源呈現出來,它須要從服務器請求資源,並將其顯示在瀏覽器窗口中,資源的格式一般是HTML,也包括PDF、image及其餘格式。
那麼從輸入URL到瀏覽器顯示完成,大體是分爲2個階段。首先解析url,完成後經過http獲取頁面資源,最後將得到的資源渲染展現出來。css
HTML頁面加載和解析流程
1.用戶輸入網址(假設是個html頁面,而且是第一次訪問),瀏覽器向服務器發出請求,服務器返回html文件;
2.瀏覽器開始載入html代碼,發現<head>標籤內有一個<link>標籤引用外部CSS文件;
3.瀏覽器又發出CSS文件的請求,服務器返回這個CSS文件;
4.瀏覽器繼續載入html中<body>部分的代碼,而且CSS文件已經拿到手了,能夠開始渲染頁面了;
5.瀏覽器在代碼中發現一個<img>標籤引用了一張圖片,向服務器發出請求。此時瀏覽器不會等到圖片下載完,而是繼續渲染後面的代碼;
6.服務器返回圖片文件,因爲圖片佔用了必定面積,影響了後面段落的排布,所以瀏覽器須要回過頭從新渲染這部分代碼;
7.瀏覽器發現了一個包含一行Javascript代碼的<script>標籤,趕快運行它;
8.Javascript腳本執行了這條語句,它命令瀏覽器隱藏掉代碼中的某個<div> (style.display=」none」)。忽然少了這麼一個元素,瀏覽器不得不從新渲染這部分代碼;
9.終於等到了</html>的到來,瀏覽器淚流滿面……
10.等等,還沒完,用戶點了一下界面中的「換膚」按鈕,Javascript讓瀏覽器換了一下<link>標籤的CSS路徑;
11.瀏覽器召集了在座的各位<div><span><ul><li>們,「大夥兒收拾收拾行李,咱得從新來過……」,瀏覽器向服務器請求了新的CSS文件,從新渲染頁面html
1. 解析url、獲取頁面資源前端
2. 解析、渲染頁面html5
DNS域名解析java
瀏覽器在發起http請求前,會先解析這個域名,找到ip地址。這個過程就是dns解析。解析過程以下:
1)瀏覽器先查詢hosts文件是否有與這個域名對應的ip地址,若是有則直接向這個ip地址發起http請求。查詢不到就進行下一步。web
2)瀏覽器向本地DNS服務器發出解析域名的DNS解析報文,本地DNS服務器收到請求後,先查詢緩存,判斷是否有對應的記錄,若是有就返回這條記錄,查詢不到就進行下一步。數據庫
3)本地DNS服務器沒有在緩存中查詢到對應的記錄,本地DNS服務器因而就向DNS根服務器發起查詢請求。DNS根服務器收到請求經過查詢獲得頂級域名對應的頂級域服務器的ip地址,而後向本地DNS服務器發送一條應答報文。瀏覽器
4)本地DNS服務器收到應答報文後,獲得頂級域服務器的地址,而後向該地址發送請求解析域名的DNS請求報文。緩存
5)頂級域名服務器在收到請求後先查詢緩存是否有對應的記錄,若是有就返回對應的記錄,若是沒有找到就查詢域名對應的二級域服務器地址,而後將域名對應的二級域服務器地址返回給本地DNS服務器。
6)本地DNS服務器收到應答報文後,獲得二級域服務器的地址,而後向該地址發送請求解析域名的DNS請求報文。
7)二級域服務器在收到請求後先查詢緩存是否有對應的記錄,若是有就返回對應的記錄,若是沒有找到就查詢域名對應的三級域服務器地址,而後將域名對應的三級域服務器地址返回給本地DNS服務器。
8)本地DNS服務器收到應答報文後,獲得三級域服務器的地址,而後向該地址發送請求解析域名的DNS請求報文。
9)三級域服務器在收到請求後在DNS區域數據庫中查詢對應的記錄,返回對應的記錄
10)本地名稱服務器在收到三級域服務器後,向用戶返回一條DNS應答報文,並將這條記錄保存在緩存中
11)瀏覽器就獲得了域名對應的ip地址,而後就能夠發起http請求了
3次握手4次揮手
ACK : TCP協議規定,只有ACK=1時有效,也規定鏈接創建後全部發送的報文的ACK必須爲1
SYN(SYNchronization):在鏈接創建時用來同步序號。當SYN=1而ACK=0時,代表這是一個鏈接請求報文。對方若贊成創建鏈接,則應在響應報文中使SYN=1和ACK=1.
所以, SYN置1就表示這是一個鏈接請求或鏈接接受報文。
FIN (finis):完,終結的意思, 用來釋放一個鏈接。當 FIN = 1
時,代表此報文段的發送方的數據已經發送完畢,並要求釋放鏈接。
1)第一次握手:創建鏈接。客戶端發送 SYN 包到服務器,Sequence Number 爲 x,進入 SYN_SENT 狀態,等待服務器確認。
2)第二次握手:服務器收到 SYN 包,對這個報文進行確認,設置 Acknowledgment Number 爲 Sequence Number + 1;同時本身也要發送 SYN 包,Sequence Number 爲 y;服務器將這些全部信息放入 SYN + ACK 包中發送給客戶發,服務器進入 SYN_RCVD 狀態。
3)第三次握手:客戶端收到 SYN + ACK 包。將 Acknowledgment Number 設爲 y + 1,即服務器發來的 Sequence Number + 1,並向服務器發送 ACK 包,發送完成後客戶端和服務器都進入 ESTABLISHED 狀態。
http相關
一般HTTP消息包括客戶機向服務器的請求消息和服務器向客戶機的響應消息。
在瀏覽器查看一個http請求的請求頭部以下:
http響應頭部
從上圖能夠看到,頭部信息包括三部分:
一、通用頭部
1)通用頭域包含請求和響應消息都支持的頭域。 2)Request URL:請求的URL地址 3)Request Method: 請求方法,get/post/put/…… 4)Status Code:狀態碼,200 爲請求成功 5)Remote Address:路由地址
二、請求頭部
1) Accept: 告訴WEB服務器本身接受什麼介質類型,*/* 表示任何類型,type/* 表示該類型下的全部子類型; 2)Accept-Charset: 瀏覽器申明本身接收的字符集 Accept-Encoding:瀏覽器申明本身接收的編碼方法,一般指定壓縮方法,是否支持壓縮,支持什麼壓縮方法 (gzip,deflate) 3)Accept-Language: 瀏覽器申明本身接收的語言。語言跟字符集的區別:中文是語言,中文有多種字符集,好比big5,gb2312,gbk等等。 4)Authorization: 當客戶端接收到來自WEB服務器的 WWW-Authenticate 響應時,該頭部來回應本身的身份驗證信息給WEB服務器。 5)Connection:表示是否須要持久鏈接。close(告訴WEB服務器或者代理服務器,在完成本次請求的響應後,斷開鏈接, 不要等待本次鏈接的後續請求了)。keep-alive(告訴WEB服務器或者代理服務器,在完成本次請求的響應後,保持鏈接,等待本次鏈接的後續請求)。 6)Referer:發送請求頁面URL。瀏覽器向 WEB 服務器代表本身是從哪一個 網頁/URL 得到/點擊 當前請求中的網址/URL。 7)User-Agent: 瀏覽器代表本身的身份(是哪一種瀏覽器)。 8)Host: 發送請求頁面所在域。 9)Cache-Control:瀏覽器應遵循的緩存機制。 no-cache(不要緩存的實體,要求如今從WEB服務器去取) max-age:(只接受 Age 值小於 max-age 值,而且沒有過時的對象) max-stale:(能夠接受過去的對象,可是過時時間必須小於 max-stale 值) min-fresh:(接受其新鮮生命期大於其當前 Age 跟 min-fresh 值之和的緩存對象) 10)Pramga:主要使用 Pramga: no-cache,至關於 Cache-Control: no-cache。 11)Range:瀏覽器(好比 Flashget 多線程下載時)告訴 WEB 服務器本身想取對象的哪部分。 12)Form:一種請求頭標,給定控制用戶代理的人工用戶的電子郵件地址。 13)Cookie:這是最重要的請求頭信息之一
三、響應頭部
1)Age:當代理服務器用本身緩存的實體去響應請求時,用該頭部代表該實體從產生到如今通過多長時間了。 2)Accept-Ranges:WEB服務器代表本身是否接受獲取其某個實體的一部分(好比文件的一部分)的請求。bytes:表示接受,none:表示不接受。 3) Cache-Control:服務器應遵循的緩存機制。 public(能夠用 Cached 內容迴應任何用戶) private(只能用緩存內容迴應先前請求該內容的那個用戶) no-cache(能夠緩存,可是隻有在跟WEB服務器驗證了其有效後,才能返回給客戶端) max-age:(本響應包含的對象的過時時間) ALL: no-store(不容許緩存) 4) Connection: 是否須要持久鏈接 close(鏈接已經關閉)。 keepalive(鏈接保持着,在等待本次鏈接的後續請求)。 Keep-Alive:若是瀏覽器請求保持鏈接,則該頭部代表但願 WEB 服務器保持鏈接多長時間(秒)。例如:Keep-Alive:300 5)Content-Encoding:WEB服務器代表本身使用了什麼壓縮方法(gzip,deflate)壓縮響應中的對象。 例如:Content-Encoding:gzip 6)Content-Language:WEB 服務器告訴瀏覽器本身響應的對象的語言。 7)Content-Length:WEB 服務器告訴瀏覽器本身響應的對象的長度。例如:Content-Length: 26012 8)Content-Range:WEB 服務器代表該響應包含的部分對象爲整個對象的哪一個部分。例如:Content-Range: bytes 21010-47021/47022 9)Content-Type:WEB 服務器告訴瀏覽器本身響應的對象的類型。例如:Content-Type:application/xml 10)Expired:WEB服務器代表該實體將在何時過時,對於過時了的對象,只有在跟WEB服務器驗證了其有效性後,才能用來響應客戶請求。 11) Last-Modified:WEB 服務器認爲對象的最後修改時間,好比文件的最後修改時間,動態頁面的最後產生時間等等。 12) Location:WEB 服務器告訴瀏覽器,試圖訪問的對象已經被移到別的位置了,到該頭部指定的位置去取。 13)Proxy-Authenticate: 代理服務器響應瀏覽器,要求其提供代理身份驗證信息。 14)Server: WEB 服務器代表本身是什麼軟件及版本等信息。 15)Refresh:表示瀏覽器應該在多少時間以後刷新文檔,以秒計。
html解析/dom樹構建
同獲取html方式獲取css/js/圖片的資源
dom樹構建過程當中,遇到link標籤、script標籤會中止dom樹構建,以獲取html的方式獲取相關資源。
解析構建css規則樹
CSS解析的過程相似於HTML解析,也是瀏覽器使用自帶的解析器進行解析,通常解析過程是由上而下,會將CSS文件解析成爲StyleSheet對象,且每一個對象都包含CSS規則。CSS規則對象包含了選擇和聲明對象,以及其餘與CSS語法對應的對象。CSS解析完成後會大體生成以下結構的CSS Rule Tree。
構建渲染樹
渲染的主要過程分爲——Render Tree(渲染樹)生成——Layout(佈局)——Paint(繪製)。
DOM樹和CSS樹結合生成Render Tree(渲染樹)——這是由可視化元素按照其顯示順序組成的樹形結構,是文檔可視化的表示,它的做用是讓瀏覽器可以按照正確的順序渲染頁面元素。Firefox中稱之爲「框架」,Webkit中的術語則是呈現器或者呈現對象。
渲染樹是和DOM元素相對應的,可是並不是所有一一對應,例如:1,非可視化元素是不會出如今渲染樹中,如「head」元素,2,若是元素的display屬性值爲「none」,也不會出如今渲染樹中(可是visibility屬性值爲「hidden」的元素會出如今渲染樹中)
佈局layout
渲染樹中並不包含位置和大小的信息,計算這些值的過程就是佈局或者重排。
佈局的過程是一個遞歸的過程,從根元素開始,遞歸遍歷部分或者全部的渲染樹結構,併爲每個須要顯示元素計算幾何信息。通常根元素位置座標(0,0),大小爲瀏覽器窗口的可見區域。
這裏涉及到兩個重要的概念reflow和repaint:
repaint(重繪):元素的某一部分屬性發生改變,如字體顏色,背景顏色等改變,尺寸並未改變,這時發生的改變過程就是repaint。
reflow(迴流): 由於瀏覽器渲染是一個由上而下的過程,當發現某部分的變化影響了佈局時,就須要倒回去從新渲染,這個過程就稱之爲reflow。reflow幾乎是無法避免的,如今一些經常使用的效果,好比樹狀目錄的摺疊、展開(實質上是元素的顯示與隱藏)等,都將引發瀏覽器的 reflow。鼠標滑過、點擊……只要這些行爲引發了頁面上某些元素的佔位面積、定位方式、邊距等屬性的變化,都會引發它內部、周圍甚至整個頁面的從新渲染。基本上能引發reflow的主要有幾個緣由:
1,網頁初始化。
2,JS操做DOM樹的時候,增長刪除元素等。
3,某些元素的尺寸改變。
4,CSS屬性的改變,
可是瀏覽器很聰明,爲了不細小的改變就進行repaint或者reflow,瀏覽器採用一種"dirty"系統,會將這些改變操做積攢一批,而後作一次reflow,這又叫異步reflow或增量異步reflow。可是有些特殊狀況不會這麼作,好比:resize窗口,改變了頁面默認的字體,等,對於這些操做,瀏覽器會立刻進行reflow。
可是有的時候,咱們本身編寫的腳本會阻止瀏覽器的這種操做,好比咱們請求下面的值的時候:offsetTop, offsetLeft, offsetWidth, offsetHeight,scrollTop/Left/Width/Height,clientTop/Left/Width/Height,IE中的 getComputedStyle(), 或 currentStyle等,若是咱們的程序運行的時候須要這些值,那麼瀏覽器須要給咱們返回最新的值,而這樣就會將當前積攢的操做執行,從而引發頻繁的reflow或者repaint。
一般reflow比repaint會耗費更多的時間,從而也就會影響性能,因此編寫代碼的時候要儘量避免過多的reflow或者repaint。減小reflow/repaint的方法:
1,修改樣式不要逐條修改,建議定義CSS樣式的class,而後直接修改元素的className。
2,不要將DOM節點的屬性值放在循環中當成循環的變量。
3,爲動畫的 HTML 元素使用 fixed 或 absoult 的 position,那麼修改他們的 CSS 是不會 reflow 的。
4,把DOM離線後修改。如設置DOM的display:none,而後進行你須要的屢次修改,而後再顯示出來,或者clone一個節點到內存中,而後隨意修改,修改完成後再與在線的交換。
5,千萬不要使用table佈局,一個微小的改變就可能引發整個table的從新佈局。
渲染頁面
在繪製階段,系統會遍歷渲染樹,而且調用呈現器將的「paint」方法,將內容顯示在屏幕上。一樣,相似於佈局過程,也分爲全局和增量兩種
性能優化
1,提高HTML加載速度
- 頁面精簡,刪除沒必要要的註釋,空格,將內嵌的JS和CSS移至外部文件,使用壓縮工具等。
- 減小文件數量,減小頁面上引入的文件數量能夠減小請求的次數,能夠合併的JS和CSS文件儘可能合併。
- 減小域名查詢,DNS查詢和解析域名須要消耗時間,減小對外部JavaScript、CSS、圖片等資源的引用,不一樣域名的使用越少越好。
- 使用緩存,重用數據。
- 優化頁面元素的加載順序。
- 使用如今CSS和合法的標籤。
- 指定圖片的大小,若是瀏覽能夠當即肯定圖片大小就不須要從新進行佈局操做。
- 根據瀏覽器類型選擇合適的策略。
- 使用壓縮工具等。
- 頁面精簡,刪除沒必要要的註釋,空格,將內嵌的JS和CSS移至外部文件,使用壓縮工具等。
2,編寫合理的CSS
首先說明CSS選擇符的匹配順序,從右到左!從右到左!從右到左!(重要的事情說三遍),因此,相似於「#nav li」 咱們覺得很簡單的規則,應該立刻就能夠匹配成功,可是,須要從右往左匹配,因此,先會去查找全部的li,而後再去肯定它的父元素是否是#nav。所以,編寫合理的CSS也能夠提升咱們的頁面行能:
- DOM的深度儘可能淺,不要嵌套過深。
- 減小inline javascript css的數量。
- 使用合法的CSS屬性。
- 不要爲ID選擇器指定類名或者標籤名。
- 避免後代選擇器,儘可能使用子選擇器。
- 避免使用通配符。
3,關於javascript標籤
對於javascript標籤首先得了解其加載和執行的特色:1,載入後當即執行,2,執行時會阻塞頁面後續的內容,針對這些特色,咱們使用javascript標籤時應該注意:
- 將全部的javascript標籤放在頁面底部,也就是body標籤閉合以前,這樣能夠保證腳本執行前已完成DOM渲染。
- 儘量合併腳本,頁面中引入的腳本越少,加載響應速度也就越快。
- 減小inline javascript的使用。
- 全部的javascript標籤會按照其引入順序依次執行,只有前面的內容解析完成纔會解析下一個,因此注意多個javascript標籤的引入順序。
- 使用defer屬性,該屬性可使腳本在文檔徹底呈現之後再執行。
- 使用async屬性,可使當前腳本沒必要等待其餘腳本的執行,也沒必要阻塞文檔的呈現。