1. 程式人生 > >天了嚕,為什麼外鏈css要放在頭部,js要放在尾部?

天了嚕,為什麼外鏈css要放在頭部,js要放在尾部?


(題圖:梵高-向日葵)


我們最開始學前端的時候都會看到教程在處理外部css,js的時候會將css放在header中,js放在body的最後。為什麼要這樣子處理,今天參考一些資料好好分析下。

為什麼外鏈css為什麼要放頭部?

首先整個頁面展示給使用者會經過html 的解析與渲染過程。

而外鏈css無論放在html的任何位置都不影響html的解析,但是影響html的渲染。

如果將css放在尾部,html的內容可以第一時間顯示出來,但是會阻塞html行內css的渲染。

瀏覽器的這個策略其實很明智的,想象一下,如果沒有這個策略,頁面首先會呈現出一個行內css樣式,待CSS下載完之後又突然變了一個模樣。使用者體驗可謂極差,而且渲染是有成本的。

如果將css放在頭部,css的下載解析是可以和html的解析同步進行的,放到尾部,要花費額外時間來解析CSS,並且瀏覽器會先渲染出一個沒有樣式的頁面,等CSS載入完後會再渲染成一個有樣式的頁面,頁面會出現明顯的閃動的現象。

為什麼script要放在尾部?

因為當瀏覽器解析到script的時候,就會立即下載執行,中斷html的解析過程,如果外部指令碼載入時間很長(比如一直無法完成下載),就會造成網頁長時間失去響應,瀏覽器就會呈現“假死”狀態,這被稱為“阻塞效應”。

具體的流程是這樣的:

  1. 瀏覽器一邊下載HTML網頁,一邊開始解析。
  2. 解析過程中,發現script標籤
  3. 暫停解析,網頁渲染的控制權轉交給JavaScript引擎
  4. 如果script標籤引用了外部指令碼,就下載該指令碼,否則就直接執行
  5. 執行完畢,控制權交還渲染引擎,恢復往下解析HTML網頁

外鏈的script包含async或者defer如何處理?

這兩個屬性只是script標籤在header標籤中使用的,如果你把它放在body後面是無效的。

script 的這兩個屬性主要用於其js檔案沒有操作DOM的情況,這時候就可以將該js指令碼設定為非同步載入,通過async或defer來標記程式碼。

async和defer的區別:

0、async和defer都僅對外部指令碼有效,對於內建而不是連線外部指令碼的script標籤,以及動態生成的script標籤不起作用。

1、async和defer雖然都是非同步的,不過使用async標誌的指令碼檔案一旦載入完成就會立即執行;而使用defer標記的指令碼檔案,會在 DOMContentLoaded 事件之前(也就是頁面DOM載入完成時)執行。

2、如果有多個js指令碼檔案,async標記不保證按照書寫的順序執行,哪個指令碼先下載結束,就先執行那個指令碼。而defer標記則會按照js指令碼書寫順序執行。

3、一般來說,如果指令碼之間沒有依賴關係,就使用async屬性,如果指令碼之間有依賴關係,就使用defer屬性。如果同時使用async和defer屬性,後者不起作用,瀏覽器行為由async屬性決定。

對於async標記,瀏覽器的解析過程是這樣的:

  • 瀏覽器開始解析HTML網頁

  • 解析過程中,發現帶有async屬性的script標籤

  • 瀏覽器繼續往下解析HTML網頁,同時並行下載script標籤中的外部指令碼

  • 指令碼下載完成,瀏覽器暫停解析HTML網頁,開始執行下載的指令碼

  • 指令碼執行完畢,瀏覽器恢復解析HTML網頁

對於defer標記,瀏覽器的解析過程是這樣的:

  • 瀏覽器開始解析HTML網頁

  • 解析過程中,發現帶有defer屬性的script標籤

  • 瀏覽器繼續往下解析HTML網頁,同時並行下載script標籤中的外部指令碼

  • 瀏覽器完成解析HTML網頁,此時再執行下載的指令碼

  

由於使用了async或defer的script會放在header中,而header又會存在外鏈css,那麼二者有順序要求嗎?

header中script和外鏈css的位置順序

先說結論:

如果在html的header中同時有js指令碼和外鏈css,js指令碼最好放外鏈css前面。

其實js的執行是依賴css樣式的。即只有css樣式全部下載完成後才會執行js。

因為如果指令碼的內容是獲取元素的樣式,寬高等CSS控制的屬性,瀏覽器是需要計算的,也就是依賴於CSS。瀏覽器無法感知指令碼內容到底是什麼,為避免樣式獲取錯誤,因而只好等前面所有的樣式下載完後,再執行JS。

但是如果css下載事件很長的話,js也無法正常執行,導致html無法正常解析出來。如果css的內容下載更快的話,是沒影響的,但反過來的話,JS就要等待了,然而這些等待的時間是完全不必要的。

(啾咪 ^.<)