- JS、CSS渲染機制
- 解析html構建DOM樹
- 解析CSS構建CSSOM樹
- 把DOM和CSSOM組合成渲染樹(Render Tree)
- 在渲染樹的基礎上進行布局,計算每個節點的幾何結構(Layout Tree)
-
把每個節點繪制到屏幕上(Painting)
當瀏覽器從服務器接收到了html文檔,并把html在內存中轉換成DOM樹,在轉換過程中如果發現某個節點上引用了CSS或者image,就會再發一個request去請求CSS或image,然后繼續執行下面的轉換,而不需要等待request的返回,當request返回后,只需要把返回的內容放入到DOM樹中對應的位置就可以了。但當引用了JS的時候,瀏覽器發送一個JS request就會一直等待該request的返回。
-
CSS應該放在頁面頂部的
head
標簽中由于Render Tree是由DOM樹和CSSOM樹組合成的,html頁面需要等到CSS解析完后才能完成渲染,所以CSS應放在
head
標簽內,優先下載解析,以避免頁面元素由于樣式缺失造成瞬間的白頁或者給用戶閃爍感。 JS應該放在
body
的底部
因為瀏覽器需要一個穩定的dom樹結構,而且js中很有可能有代碼直接改變了dom樹結構,瀏覽器為了防止出現js修改dom樹,需要重新構建dom樹的情況,所以就會阻塞其他的下載和呈現。
將JavaScript放在head內和body底部的區別也在于此,放在head里面,由于瀏覽器發現head里面有JavaScript標簽就會暫時停止其他渲染行為,等待JavaScript下載并執行完成才能接著往下渲染,而這個時候由于在head里面這個時候頁面是白的;如果將JavaScript放在頁面底部,render Tree已經完成大部分,所以此時頁面有內容呈現,即使遇到JavaScript阻塞渲染,也不會有白屏出現
- 如果CSS和JS都在
head
標簽內,則應將JS放在所有CSS的前面
JS的執行有可能依賴最新樣式。比如,可能會有
var width=$('#id').width
,這意味著,JS代碼在執行前,瀏覽器必須保證在此JS之前的所有CSS(無論外鏈還是內嵌)都已下載和解析完成。
而嵌入的JS會阻塞后面的資源加載,所以當head中js放在CSS后面時,就會出現CSS阻塞下載的情況。
參考:
http://www.haorooms.com/post/web_xnyh_jscss
把JS放在CSS后會導致頁面阻塞,去等待CSS的下載。
另外如果要在head
引入JS盡量將JS內嵌。
-
async
和defer
也可以達到不阻塞渲染的效果- 帶有
defer
屬性的<script>
標簽可以放置在文檔的任何位置。對應的 JavaScript 文件將在頁面解析到<script>
標簽時開始下載,但不會執行,直到 DOM 加載完成,即onload事件觸發前才會被執行。當一個帶有defer
屬性的 JavaScript 文件下載時,它不會阻塞瀏覽器的其他進程,因此這類文件可以與其他資源文件一起并行下載。
但是
- 帶有
defer
屬性只被 IE 4 和 Firefox 3.5 更高版本的瀏覽器所支持,所以它不是一個理想的跨瀏覽器解決方案。在其他瀏覽器中,defer
屬性會被直接忽略,因此<script>
標簽會以默認的方式處理,也就是說會造成阻塞。然而,如果您的目標瀏覽器支持的話,這仍然是個有用的解決方案。
-
async
的作用和defer
一樣,能夠異步地加載和執行腳本,不因為加載腳本而阻塞頁面的加載。
但是
在有
async
的情況下,JavaScript 腳本一旦下載好了就會執行,所以很有可能不是按照原本的順序來執行的。如果 JavaScript 腳本前后有依賴性,使用async
就很有可能出現錯誤。
參考:
網頁性能之HTML,CSS,JavaScript
http://www.zhihu.com/question/20357435/answer/14878543
JavaScript 的性能優化:加載和執行
瀏覽器工作原理:How browsers work
前端文摘:深入解析瀏覽器的幕后工作原理
本文版權屬吳天喬所有,轉載務必注明出處。
如有錯誤,歡迎指出。