JS一定要放在Body的最底部麼?

2022-09-07 06:15:12 字數 3091 閱讀 2589

這樣的**放在body最底部? (為了溝通效率,我會提前和對方約定所有的討論都以chrome為例)

應聘者一般會回答:因為瀏覽器生成dom樹的時候是一行一行讀html**的,script標籤放在最後面就不會影響前面的頁面的渲染。

我很雞賊地接著問:既然dom樹完全生成好後頁面才能渲染出來,瀏覽器又必須讀完全部html才能生成完整的dom樹,script標籤不放在body底部是不是也一樣?留一

段空白讓

你先想一

想嚴格來說,我的最後一問是有歧義的:我們需要統一一下什麼叫我們經常掛在嘴邊的「頁面渲染出來了」 —— 指的是是 「首屏顯示出來了」 還是 「頁面完整地載入好了」(後面統稱stepc) ?如果指的是首屏顯示出來了,那麼問題又來了:假設網頁眉屏有,這裡的「首屏」 指的是 「顯示了全部的首屏」(後面統稱stepb) 還是 「沒有的首屏」(後面統稱stepa)。

確定清楚 「頁面渲染出來了」 指的是 stepa、stepb、stepc 中的哪乙個是非常關鍵的(雖然至今還沒有乙個應聘者嘗試這麼做過),如果 「頁面渲染出來了」 指的是 stepc,那麼我的最後一問的答案是肯定的——script標籤不放在body底部不會拖慢頁面完整地載入好的時間。

顯然,我們往往更關心首屏時間,所以,如果 「頁面渲染出來了」 特指「沒有的首屏」,那我的最後一問變成了下面這樣,又該如何回答呢?

既然dom樹完全生成好後才能顯示「沒有的首屏」,瀏覽器又必須讀完全部html才能生成完整的dom樹,script標籤不放在body底部是不是也一樣?

然而上面的問題還是存在乙個陷阱——既然dom樹完全生成好後才能顯示「沒有的首屏」這句話是帶欺騙性的,「沒有的首屏」並不以「完整的dom樹」為必要條件。也就是說: 在生成dom樹的過程中只要某些條件具備了,「沒有的首屏」就能顯示出來。

所以,拋開這些歧義和陷阱,我的問題變成了:

script標籤的位置會影響首屏時間麼?

然而答案並不是那麼顯而易見,這得從瀏覽器的渲染機制說起。 (再一次說明:本文所說的瀏覽器都是指chrome)

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是更優的。具體可以看 這裡

1、create/update dom and request css/image/js:瀏覽器請求到html**後,在生成dom的最開始階段(應該是 bytes → characters 後),並行發起css、、js的請求,無論他們是否在head裡。

4、layout:有了render tree,瀏覽器已經能知道網頁中有哪些節點、各個節點的css定義以及他們的從屬關係。下一步操作稱之為layout,顧名思義就是計算出每個節點在螢幕中的位置。

5、painting:layout後,瀏覽器已經知道了哪些節點要顯示(which nodes are visible)、每個節點的css屬性是什麼(their computed styles)、每個節點在螢幕中的位置是**(geometry)。就進入了最後一步:painting,按照算出來的規則,通過顯示卡,把內容畫到螢幕上。

以上五個步驟前3個步驟之所有使用 「create/update」 是因為dom、cssom、render tree都可能在第一次painting後又被更新,比如js修改了dom或者css屬性。

我把扒了一段有讚pc首頁的**到本地,通過node跑起來。node作為server端,對/js/jquery.js做了延時2s返回的處理,並且把放到導航欄的下面,結果是這樣的:

從上面的timeline我們可以看出:

回到前面的問題:

script標籤的位置會影響首屏時間麼?

答案是:不影響但有可能截斷首屏的內容,使其只顯示上面一部分

所以,總算弄清楚這個眾所周知的常識了。但設計開發中可能會遇到難以把所有的js放到頁面最底部的情形。比如:你的頁面是分模組來寫的,每乙個模組都有自己的html、js甚至css,當把這些模組湊到乙個頁面中的時候就會出現js自然而然地出現在html中間部分。

我們也遇到了這樣的問題,所以就做了乙個開源專案: tiny-loader —— a small loader that load css/js in best way for page performance 簡單好用。

回答下題目中所提到的問題,js一定要放在body的最底部麼? 如果用了tiny-loader,js可以不放在body最底部。

DNS MX記錄一定要放在A記錄之前

dns mx記錄一定要放在a記錄之前,否則和郵件字尾相匹配的網域名稱沒有指向郵件伺服器,則郵件伺服器相應字尾的郵箱收不到郵件 舉例如下 我的mail字尾為wa wa.dns mx記錄為mail.wa wa.郵件伺服器ip為210.75.18.37,wa wa.指向211.96.97.30,mail....

main方法一定要放在public類當中嗎?

答案是 否 今天在寫小練習的時候發現,main函式沒有放在public類中執行的時候報錯如下 原以為main函式必須放在public類裡面才行,因為將public挪到item類處後就可以執行了 後來通過查閱資料發現,想呼叫main方法跟這個類是不是public的並沒有關係。之所以前面報錯是因為ecl...

為什麼wait 一定要放在迴圈中

在多執行緒的程式設計實踐中,wait 的使用方法如下 synchronized monitor 處理其他的業務邏輯 那為什麼非要while判斷,而不採用if判斷呢?如下 synchronized monitor 處理其他的業務邏輯 這是因為,如果採用if判斷,當執行緒從wait中喚醒時,那麼將直接執...