CSS 和 JS 阻塞二三事

都放假了吧,祝你們春節快樂,沒對象的都相親成功,有對象的也相親成功~javascript

瀏覽器渲染步驟

網頁渲染過程:css

  1. 將 HTML 解析成 DOM Tree,同時將 CSS 解析成 CSSOM Tree
  2. 將 DOM Tree 和 CSSOM Tree 合併成 Render Tree
  3. 生成佈局 Layout ,計算 Render Tree 中元素的尺寸、位置
  4. 將 Render Tree 繪製成像素點,最後顯示在屏幕上

上面的過程是由 GUI 渲染線程完成的。html

瀏覽器內核(渲染進程)

瀏覽器內有多個進程,其中渲染進程被稱爲瀏覽器內核,負責頁面渲染和執行 JS 腳本等。渲染進程負責瀏覽器的解析和渲染,內部有 JS 引擎線程、 GUI 渲染線程、事件循環管理線程、定時器線程、HTTP 線程。java

JS 引擎線程負責執行 JS 腳本,GUI 渲染線程負責頁面的解析和渲染,二者是互斥的,也就是執行 JS 的時候頁面是中止解析和渲染的。這是由於若是在頁面渲染的同時 JS 引擎修改了頁面元素,好比清空頁面,會形成後續頁面渲染的沒必要要和錯誤。而因爲 JS 常常要操做 DOM ,就要涉及 JS 引擎線程和 GUI 渲染線程的通訊,而線程間通訊代價是很是昂貴的,這也是形成 JS 操做 DOM 效率不高的緣由。jquery

解析、渲染與阻塞

本文例子須要在控制檯切換到弱網且無緩衝模式下進行測試: npm

瀏覽器的 HTML/CSS 的解析和渲染都屬於 GUI渲染線程,因此和 JS 引擎線程是互斥、阻塞的。下面從代碼實際運行的角度分析瀏覽器解析和渲染的順序,以及互相間的阻塞關係:bootstrap

CSS 阻塞

  1. css 文件的下載和解析不會影響 DOM 的解析,可是會阻塞 DOM 的渲染。由於 CSSOM Tree 要和 DOM Tree 合成 Render Tree 才能繪製頁面。下面的 test1 在 css 下載並解析完成前是默認樣式, test2 在 css 下載並解析完成以前不會顯示:
<button class="btn btn-primary">test1</button>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<div>test2</div>
複製代碼
  1. css 文件沒下載並解析完成以前,後續的 js 腳本不能執行。下面的 alert('ok') 在 css 下載並解析完成以前不會彈出來:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
<script> alert('ok') </script>
複製代碼
  1. css 文件的下載不會阻塞前面的 js 腳本執行。下面的 alert('ok') 會在 css 下載完成前彈出:
<script> alert('ok') </script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
複製代碼

因此在須要提早執行不操做 dom 元素的 js 時,不妨把 js 放到 css 文件以前。瀏覽器

js 阻塞

js 文件的下載和解析會阻塞 GUI 渲染進程,也就是會阻塞 DOM 和 CSS 的解析和渲染。網絡

  1. js 文件沒下載並解析完成以前,後續的 HTML 和 CSS 沒法解析:
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
    <div>test</div>
複製代碼
  1. js 文件的下載不會阻塞前面 HTML 和 CSS 的解析:
<div>test</div>
    <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
複製代碼

須要注意的點

第一,GUI 渲染線程會盡量早的將內容呈現到屏幕上,並不會等到全部的 HTML 都解析完成以後再去構建和佈局 Render Tree,而是解析完一部份內容就顯示一部份內容,同時,可能還在經過網絡下載其他內容。下面 test1 會在 js 文件下載完成前渲染完成,而 test2 則會在 js 文件下載並執行完以後渲染:dom

<div>test1</div>
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
  <div>test2</div>
複製代碼

第二,文件的下載是不會被阻塞的,無論是 css 仍是 js 文件,瀏覽器的主線程會在頁面解析前開啓下載,因此就算在外部腳本執行前刪除腳本,腳本也仍是會下載。

<body>
  <script> document.body.remove() </script>  
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css">
  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>
</body>
複製代碼

總結

總之,無論是下載 js 文件仍是 css 文件,都會阻塞下面頁面的渲染,但不會阻塞前面的渲染,符合咱們預期的編碼邏輯。

相關文章
相關標籤/搜索