留
一
段
空
白
讓
你
先
想
一
想
這其實是個開放性的問題,里面涉及的概念的界定本身就很重要。
嚴格來說,我的最后一問是有歧義的:我們需要統一一下什么叫我們經常掛在嘴邊的“頁面渲染出來了” —— 指的是是 “首屏顯示出來了” 還是 “頁面完整地加載好了”(后面統稱StepC) ?
如果指的是首屏顯示出來了,那么問題又來了:假設網頁首屏有圖片,這里的“首屏” 指的是 “顯示了全部圖片的首屏”(后面統稱StepB) 還是 “沒有圖片的首屏”(后面統稱StepA)。
確定清楚 “頁面渲染出來了” 指的是 StepA、StepB、StepC 中的哪一個是非常關鍵的(雖然至今還沒有一個應聘者嘗試這么做過),如果 “頁面渲染出來了” 指的是 StepC,那么我的最后一問的答案是肯定的——script標簽不放在body底部不會拖慢頁面完整地加載好的時間。
顯然,我們往往更關心首屏時間,所以,如果 “頁面渲染出來了” 特指“沒有圖片的首屏”,那我的最后一問變成了下面這樣,又該如何回答呢?
既然Dom樹完全生成好后才能顯示“沒有圖片的首屏”,瀏覽器又必須讀完全部HTML才能生成完整的Dom樹,script標簽不放在body底部是不是也一樣?
然而上面的問題還是存在一個陷阱——既然Dom樹完全生成好后才能顯示“沒有圖片的首屏”這句話是帶欺騙性的,“沒有圖片的首屏”並不以“完整的Dom樹”為必要條件。也就是說:在生成Dom樹的過程中只要某些條件具備了,“沒有圖片的首屏”就能顯示出來。
所以,拋開這些歧義和陷阱,我的問題變成了:
script標簽的位置會影響首屏時間么?
然而答案並不是那么顯而易見,這得從瀏覽器的渲染機制說起。(再一次說明:本文所說的瀏覽器都是指chrome)
Google Web Fundamentals 是一個非常優秀的文檔,里面講到了跟web、瀏覽器、前端的方方面面。我總結一下其中的 Ilya Grigorik 寫的 Critical rendering path 瀏覽器渲染機制部分的內容如下:
1、DOM:Document Object Model,瀏覽器將HTML解析成樹形的數據結構,簡稱DOM。
2、CSSOM:CSS Object Model,瀏覽器將CSS代碼解析成樹形的數據結構。
3、DOM 和 CSSOM 都是以 Bytes → characters → tokens → nodes → object model. 這樣的方式生成最終的數據。如下圖所示:

DOM 樹的構建過程是一個深度遍歷過程:當前節點的所有子節點都構建好后才會去構建當前節點的下一個兄弟節點。
4、Render Tree:DOM 和 CSSOM 合並后生成 Render Tree,如下圖:

Render Tree 和DOM一樣,以多叉樹的形式保存了每個節點的css屬性、節點本身屬性、以及節點的孩子節點。
注意:display:none 的節點不會被加入 Render Tree,而 visibility: hidden 則會,所以,如果某個節點最開始是不顯示的,設為 display:none 是更優的。(具體可以看這里)
以上五個步驟前3個步驟之所有使用 “Create/Update” 是因為DOM、CSSOM、Render Tree都可能在第一次Painting后又被更新多次,比如JS修改了DOM或者CSS屬性。
Layout 和 Painting 也會被重復執行,除了DOM、CSSOM更新的原因外,圖片下載完成后也需要調用Layout 和 Painting來更新網頁。
我扒了一段有贊PC首頁的代碼到本地,通過Node跑起來。Node作為Server端,對/js/jQuery.js 做了延時2s返回的處理,並且把<script src="http://127.0.0.1:8080/js/jquery.js"></script> 放到導航欄的下面,結果是這樣的:




從上面的Timeline我們可以看出:
回到前面的問題:
script標簽的位置會影響首屏時間么?
答案是:不影響(如果這里里的首屏指的是頁面從白板變成網頁畫面——也就是第一次Painting),但有可能截斷首屏的內容,使其只顯示上面一部分。
為什么說是“有可能”呢?,如果該js下載地比css還快,或者script標簽不在第一屏的html里,實際上是不影響的。明白這一影響邊界非常重要,這樣我們在考察頁面性能瓶頸的時候就有的放矢了。舉個例子:在網頁的第二屏有一個通用模塊,實際上我們是可以把它的js邏輯獨立成一個文件,將模塊的html和js標簽放在一起做成獨立的模板引進來的(如果它的js比較小或者說因為多了一個文件會多占用一個TCP連接和帶寬,這實際上是另外一個話題了,請參考我文章開頭的聲明)。
本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。