瀏覽器解析URL的過程


一、基本過程

1、概念:瀏覽器的內核分為兩個核心部分,渲染引擎與js引擎,拿Chrome來說,它的渲染引擎是webkit渲染引擎,js引擎為v8。渲染引擎用來渲染窗口,可以顯示html,xml,xhtml,圖片等,也可以通過插件渲染其他的文件。例如PDF,在此不做討論。

2、請求過程

在瀏覽器地址欄輸入url地址,按下回車鍵
瀏覽器獲取url進行域名解析,首先從本地DNS緩存查找,如果本地沒有則去DNS服務器查找,如果都沒有找到,則瀏覽器返回請求失敗
DNS解析出請求地址,瀏覽器想這個地址發送請求
進行tcp三次握手建立連接
tcp/ip連接建立后,瀏覽器向服務器發送http請求,服務處理請求並返回相應的資源(如果有緩存就在緩存中去)
客戶端下載資源,瀏覽器將內容展示到窗口
3、渲染過程

渲染引擎解析html生成DOM Tree,此時display:none的元素也存在與DOM Tree
渲染引擎解析css生成CSS Rule Tree(css規則樹)
通過js引擎來解析Javascript腳本,主要是通過DOM API和CSSOM API來操作DOM Tree和CSS Rule Tree.
DOM Tree 與CSS Rule Tree結合生成Render Tree(渲染樹),這時display:none的元素已不存在與render tree中
然后計算每個DOM節點的位置大小等,根據渲染樹來布局,這一過程叫reflow(回流)
最后調用系統Native GUI API進行繪制(重繪)
4、渲染過程遇到js文件怎么處理?

JavaScript的加載、解析與執行會阻塞DOM的構建,也就是說,在構建DOM時,HTML解析器若遇到了JavaScript,那么它會暫停構建DOM,將控制權移交給JavaScript引擎,等JavaScript引擎運行完畢,瀏覽器再從中斷的地方恢復DOM構建。

也就是說,如果你想首屏渲染的越快,就越不應該在首屏就加載 JS 文件,這也是都建議將 script 標簽放在 body 標簽底部的原因。當然在當下,並不是說 script 標簽必須放在底部,因為你可以給 script 標簽添加 defer 或者 async 屬性(下文會介紹這兩者的區別)。

JS文件不只是阻塞DOM的構建,它會導致CSSOM也阻塞DOM的構建。

原本DOM和CSSOM的構建是互不影響,井水不犯河水,但是一旦引入了JavaScript,CSSOM也開始阻塞DOM的構建,只有CSSOM構建完畢后,DOM再恢復DOM構建。

這是什么情況?

這是因為JavaScript不只是可以改DOM,它還可以更改樣式,也就是它可以更改CSSOM。前面我們介紹,不完整的CSSOM是無法使用的,但JavaScript中想訪問CSSOM並更改它,那么在執行JavaScript時,必須要能拿到完整的CSSOM。所以就導致了一個現象,如果瀏覽器尚未完成CSSOM的下載和構建,而我們卻想在此時運行腳本,那么瀏覽器將延遲腳本執行和DOM構建,直至其完成CSSOM的下載和構建。也就是說,在這種情況下,瀏覽器會先下載和構建CSSOM,然后再執行JavaScript,最后在繼續構建DOM。

5、回流與重繪

回流:當render tree中的一部分(或全部)因為元素的規模尺寸、布局、隱藏等改變而需要重新構建
重繪:當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀、風格,而不會影響布局的,比如background-color
       回流必定會發生重繪,重繪不一定會引發回流。重繪和回流會在我們設置節點樣式時頻繁出現,同時也會很大程度上影響性能。回流所需的成本比重繪高的多,改變父節點里的子節點很可能會導致父節點的一系列回流。

6、常見引起回流的屬性和方法

添加或者刪除可見的DOM元素;
元素尺寸改變——邊距、填充、邊框、寬度和高度
內容變化,比如用戶在input框中輸入文字
瀏覽器窗口尺寸改變——resize事件發生時
計算 offsetWidth 和 offsetHeight 屬性
設置 style 屬性的值
7、如何減少回流和重繪

使用 transform 替代 top
使用 visibility 替換 display: none ,因為前者只會引起重繪,后者會引發回流(改變了布局)
不要把節點的屬性值放在一個循環里當成循環里的變量
不要使用 table 布局,可能很小的一個小改動會造成整個 table 的重新布局
動畫實現的速度的選擇,動畫速度越快,回流次數越多,也可以選擇使用 requestAnimationFrame
CSS 選擇符從右往左匹配查找,避免節點層級過多
將頻繁重繪或者回流的節點設置為圖層,圖層能夠阻止該節點的渲染行為影響別的節點。比如對於 video 標簽來說,瀏覽器會自動將該節點變為圖層
8、為什么操作DOM慢

因為 DOM 是屬於渲染引擎中的東西,而 JS 又是 JS 引擎中的東西。當我們通過 JS 操作 DOM 的時候,其實這個操作涉及到了兩個線程之間的通信,那么勢必會帶來一些性能上的損耗。操作 DOM 次數一多,也就等同於一直在進行線程之間的通信,並且操作 DOM 可能還會帶來重繪回流的情況,所以也就導致了性能上的問題。

9、渲染問題

FOUC:由於瀏覽器渲染機制(比如firefox),再CSS加載之前,先呈現了HTML,就會導致展示出無樣式內容,然后樣式突然呈現的現象;

白屏:有些瀏覽器渲染機制(比如chrome)要先構建DOM樹和CSSOM樹,構建完成后再進行渲染,如果CSS部分放在HTML尾部,由於CSS未加載完成,瀏覽器遲遲未渲染,從而導致白屏;也可能是把js文件放在頭部,腳本會阻塞后面內容的呈現,腳本會阻塞其后組件的下載,出現白屏問題。

10、defer與async

 

11、結論

瀏覽器工作流程:構建DOM -> 構建CSSOM -> 構建渲染樹 -> 布局 -> 繪制。
CSSOM會阻塞渲染,只有當CSSOM構建完畢后才會進入下一個階段構建渲染樹。
通常情況下DOM和CSSOM是並行構建的,但是當瀏覽器遇到一個script標簽時,DOM構建將暫停,直至腳本完成執行。但由於JavaScript可以修改CSSOM,所以需要等CSSOM構建完畢后再執行JS。
如果你想首屏渲染的越快,就越不應該在首屏就加載 JS 文件,建議將 script 標簽放在 body 標簽底部。

二、性能優化
 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屬性,可以使當前腳本不必等待其他腳本的執行,也不必阻塞文檔的呈現。

三、 結語

       關於瀏覽器渲染的內容基本就是這些了,下面引用網上一篇比較好相關文章中的一段做個總結:

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文件,重新渲染頁面

 如果需要了解更多詳細的內容,請參閱下面的資料。
     參考資料:

     1,權威資料:how browsers work(英文,特別長,但是很權威);

      2,如果看英文有困難的可以看看下面的翻譯版本——瀏覽器工作原理簡介。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM