1. 程式人生 > >瀏覽器的解析和執行過程

瀏覽器的解析和執行過程

們的 由於 繼續 動畫 table 就會 內嵌 cnblogs 內嵌腳本

當瀏覽器獲得一個html文件時,會“自上而下”加載,並在加載過程中進行解析渲染。 解析: 1. 瀏覽器會將HTML解析成一個DOM樹(display:none,visibility:hidden)。DOM 樹的構建過程是一個深度遍歷過程:當前節點的所有子節點都構建好後才會去構建當前節點的下一個兄弟節點。 2. 將CSS解析成 CSS Rule Tree 。 3. 根據DOM樹和CSSOM來構造 Rendering Tree( visibility:hidden )。 4.有了Render Tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的CSS定義以及他們的從屬關系。下一步Layout 5.再下一步就是繪制,即遍歷render樹,並使用UI後端層繪制每個節點。 過程是這樣的: 技術分享 技術分享

技術分享

技術分享 上述這個過程是逐步完成的,為了更好的用戶體驗,渲染引擎將會盡可能早的將內容呈現到屏幕上,並不會等到所有的html都解析完成之後再去構建和布局render樹。它是解析完一部分內容就顯示一部分內容,同時,可能還在通過網絡下載其余內容。(這段話是《how browsers work》裏面講的,讓我茅塞頓開) 幾個概念: (1)Reflow(回流):瀏覽器要花時間去渲染,當它發現了某個部分發生了變化影響了布局,那就需要倒回去重新渲染。 (2)Repaint(重繪):如果只是改變了某個元素的背景顏色,文字顏色等,不影響元素周圍或內部布局的屬性,將只會引起瀏覽器的repaint,重畫某一部分。 Reflow要比Repaint更花費時間,也就更影響性能。所以在寫代碼的時候,要盡量避免過多的Reflow。

reflow的原因
: (1)頁面初始化的時候; (2)操作DOM時; (3)某些元素的尺寸變了; (4)如果 CSS 的屬性發生變化了。 減少 reflow/repaint  (1)不要一條一條地修改 DOM 的樣式。與其這樣,還不如預先定義好 css 的 class,然後修改 DOM 的 className。  (2)不要把 DOM 結點的屬性值放在一個循環裏當成循環裏的變量。  (3)為動畫的 HTML 元件使用 fixed 或 absoult 的 position,那麽修改他們的 CSS 是不會 reflow 的。  (4)千萬不要使用 table 布局。因為可能很小的一個小改動會造成整個 table 的重新布局。 編寫CSS時應該註意:
CSS選擇符是從右到左進行匹配的。從右到左!所以,#nav li 我們以為這是一條很簡單的規則,秒秒鐘就能匹配到想要的元素,但是,但是,但是,是從右往左匹配啊,所以,會去找所有的li,然後再去確定它的父元素是不是#nav。,因此,寫css的時候需要註意: 關於script標簽的位置 現在,我們大都會將script標簽放在body結束標簽之前,那原因是什麽呢?我今天也做了一個測試。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>測試js代碼位置</title>
  6. <script type="text/javascript">
  7. var item = document.getElementById("item");
  8. cosole.log(item);
  9. </script>
  10. </head>
  11. <body>
  12. <div id="item" width="100px" height="100px">
  13. 你好
  14. </div>
  15. </body>
  16. </html>
js 的加載特點: (1)載入後馬上執行,哪怕瀏覽器還在渲染html (2)執行時會阻塞頁面後續的內容(包括頁面的渲染、其它資源的下載)。原因:因為瀏覽器需要一個穩定的DOM樹結構,而JS中很有可能有 代碼直接改變了DOM樹結構,比如使用 document.write 或 appendChild,甚至是直接使用的location.href進行跳轉,瀏覽器為了防止出現JS修 改DOM樹,需要重新構建DOM樹的情況,所以 就會阻塞其他的下載和呈現。所以,js 死循環執行不完的話,頁面也就別想呈現了; 減少 JavaScript 對性能的影響的方法: 將所有的script標簽放到頁面底部,也就是body閉合標簽之前,這能確保在腳本執行前頁面已經完成了DOM樹渲染。 盡可能地合並腳本。頁面中的script標簽越少,加載也就越快,響應也越迅速。無論是外鏈腳本還是內嵌腳本都是如此。 采用無阻塞下載 JavaScript 腳本的方法: (1)使用script標簽的 defer 屬性; (2)使用動態創建的script元素來下載並執行代碼; 所以,總結一下,一個瀏覽器完整的加載順序:

1. 用戶輸入網址(假設是個 HTML 頁面,並且是第一次訪問),瀏覽器拿到 HTML 文件準備解析成Dom tree;

2. 瀏覽器開始載入 HTML 代碼,發現 <head> 標簽內有一個 <link> 標簽引用外部 CSS 文件;

3. 瀏覽器又發出 CSS 文件的請求,服務器返回這個 CSS 文件, 準備解析成CSS tree;

4. 瀏覽器繼續載入 HTML 中 <body> 部分的代碼,並且 CSS 文件已經拿到手了,可以layout;

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 和 CSS 代碼質量參差不齊,說不定哪天跑著跑著就掛掉了。好在這個世界還有這麽一群人——頁面重構工程師,平時挺不起眼,也就幫視覺設計師們切切圖啊改改字,其實背地裏還是幹了不少實事的。

瀏覽器的解析和執行過程