日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

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

發(fā)布時(shí)間:2025/5/22 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JS一定要放在Body的最底部么? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、從一個(gè)面試題說(shuō)起

面試前端的時(shí)候我喜歡問(wèn)一些看上去是常識(shí)的問(wèn)題。比如:為什么大家普遍把?<script src=""></script>?這樣的代碼放在body最底部??(為了溝通效率,我會(huì)提前和對(duì)方約定所有的討論都以chrome為例)

應(yīng)聘者一般會(huì)回答:因?yàn)闉g覽器生成Dom樹(shù)的時(shí)候是一行一行讀HTML代碼的,script標(biāo)簽放在最后面就不會(huì)影響前面的頁(yè)面的渲染。

我很雞賊地接著問(wèn):既然Dom樹(shù)完全生成好后頁(yè)面才能渲染出來(lái),瀏覽器又必須讀完全部HTML才能生成完整的Dom樹(shù),script標(biāo)簽不放在body底部是不是也一樣?

留?一?段?空?白?讓?你?先?想?一?想

“頁(yè)面渲染出來(lái)了” 指的是什么?

嚴(yán)格來(lái)說(shuō),我的最后一問(wèn)是有歧義的:我們需要統(tǒng)一一下什么叫我們經(jīng)常掛在嘴邊的“頁(yè)面渲染出來(lái)了” —— 指的是是 “首屏顯示出來(lái)了” 還是 “頁(yè)面完整地加載好了”(后面統(tǒng)稱StepC) ?如果指的是首屏顯示出來(lái)了,那么問(wèn)題又來(lái)了:假設(shè)網(wǎng)頁(yè)首屏有圖片,這里的“首屏” 指的是 “顯示了全部圖片的首屏”(后面統(tǒng)稱StepB) 還是 “沒(méi)有圖片的首屏”(后面統(tǒng)稱StepA)。

確定清楚 “頁(yè)面渲染出來(lái)了” 指的是 StepA、StepB、StepC 中的哪一個(gè)是非常關(guān)鍵的(雖然至今還沒(méi)有一個(gè)應(yīng)聘者嘗試這么做過(guò)),如果 “頁(yè)面渲染出來(lái)了” 指的是 StepC,那么我的最后一問(wèn)的答案是肯定的——script標(biāo)簽不放在body底部不會(huì)拖慢頁(yè)面完整地加載好的時(shí)間。

顯然,我們往往更關(guān)心首屏?xí)r間,所以,如果 “頁(yè)面渲染出來(lái)了” 特指“沒(méi)有圖片的首屏”,那我的最后一問(wèn)變成了下面這樣,又該如何回答呢?

既然Dom樹(shù)完全生成好后才能顯示“沒(méi)有圖片的首屏”,瀏覽器又必須讀完全部HTML才能生成完整的Dom樹(shù),script標(biāo)簽不放在body底部是不是也一樣?

陷阱

然而上面的問(wèn)題還是存在一個(gè)陷阱——?既然Dom樹(shù)完全生成好后才能顯示“沒(méi)有圖片的首屏”?這句話是帶欺騙性的,“沒(méi)有圖片的首屏”并不以“完整的Dom樹(shù)”為必要條件。也就是說(shuō):?在生成Dom樹(shù)的過(guò)程中只要某些條件具備了,“沒(méi)有圖片的首屏”就能顯示出來(lái)。

所以,拋開(kāi)這些歧義和陷阱,我的問(wèn)題變成了:

script標(biāo)簽的位置會(huì)影響首屏?xí)r間么?

然而答案并不是那么顯而易見(jiàn),這得從瀏覽器的渲染機(jī)制說(shuō)起。?(再一次說(shuō)明:本文所說(shuō)的瀏覽器都是指chrome)

二、瀏覽器的渲染機(jī)制

首先,我們需要了解幾個(gè)概念:

1、?DOM?:Document Object Model,瀏覽器將HTML解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu),簡(jiǎn)稱DOM。

2、?CSSOM?:CSS Object Model,瀏覽器將CSS代碼解析成樹(shù)形的數(shù)據(jù)結(jié)構(gòu)。

3、DOM 和 CSSOM 都是以?Bytes → characters → tokens → nodes → object model.?這樣的方式生成最終的數(shù)據(jù)。如下圖所示:

DOM樹(shù)的構(gòu)建過(guò)程是一個(gè)深度遍歷過(guò)程:當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)都構(gòu)建好后才會(huì)去構(gòu)建當(dāng)前節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)。

4、?Render Tree?:DOM 和 CSSOM 合并后生成 Render Tree,如下圖:

Render Tree 和DOM一樣,以多叉樹(shù)的形式保存了每個(gè)節(jié)點(diǎn)的css屬性、節(jié)點(diǎn)本身屬性、以及節(jié)點(diǎn)的孩子節(jié)點(diǎn)。

注意:display:none 的節(jié)點(diǎn)不會(huì)被加入Render Tree,而visibility: hidden 則會(huì),所以,如果某個(gè)節(jié)點(diǎn)最開(kāi)始是不顯示的,設(shè)為display:none是更優(yōu)的。具體可以看?這里

瀏覽器的渲染過(guò)程:

1、?Create/Update DOM And request css/image/js?:瀏覽器請(qǐng)求到HTML代碼后,在生成DOM的最開(kāi)始階段(應(yīng)該是 Bytes → characters 后),并行發(fā)起css、圖片、js的請(qǐng)求,無(wú)論他們是否在HEAD里。

注意:發(fā)起js文件的下載request并不需要DOM處理到那個(gè)script節(jié)點(diǎn),比如:簡(jiǎn)單的正則匹配就能做到這一點(diǎn),雖然實(shí)際上并不一定是通過(guò)正則:)。這是很多人在理解渲染機(jī)制的時(shí)候存在的誤區(qū)

2、?Create/Update Render CSSOM?:CSS文件下載完成,開(kāi)始構(gòu)建CSSOM

3、?Create/Update Render Tree?:所有CSS文件下載完成,CSSOM構(gòu)建結(jié)束后,和 DOM 一起生成 Render Tree。

4、?Layout?:有了Render Tree,瀏覽器已經(jīng)能知道網(wǎng)頁(yè)中有哪些節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的CSS定義以及他們的從屬關(guān)系。下一步操作稱之為?Layout?,顧名思義就是計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。

5、?Painting?:Layout后,瀏覽器已經(jīng)知道了哪些節(jié)點(diǎn)要顯示(which nodes are visible)、每個(gè)節(jié)點(diǎn)的CSS屬性是什么(their computed styles)、每個(gè)節(jié)點(diǎn)在屏幕中的位置是哪里(geometry)。就進(jìn)入了最后一步:?Painting?,按照算出來(lái)的規(guī)則,通過(guò)顯卡,把內(nèi)容畫(huà)到屏幕上。

以上五個(gè)步驟前3個(gè)步驟之所有使用 “Create/Update” 是因?yàn)镈OM、CSSOM、Render Tree都可能在第一次Painting后又被更新,比如JS修改了DOM或者CSS屬性。

Layout 和 Painting 也會(huì)被重復(fù)執(zhí)行,除了DOM、CSSOM更新的原因外,圖片下載完成后也需要調(diào)用Layout 和 Painting來(lái)更新網(wǎng)頁(yè)。

看Timeline,一目了然

我把扒了一段有贊PC首頁(yè)的代碼到本地,通過(guò)Node跑起來(lái)。Node作為Server端,對(duì)?/js/jquery.js?做了延時(shí)2s返回的處理,并且把?<script src="http://127.0.0.1:8080/js/jquery.js"></script>?放到導(dǎo)航欄的下面,結(jié)果是這樣的:

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

  • 首屏?xí)r間和DomContentLoad事件沒(méi)有必然的先后關(guān)系
  • 所有CSS盡早加載是減少首屏?xí)r間的最關(guān)鍵
  • js的下載和執(zhí)行會(huì)阻塞Dom樹(shù)的構(gòu)建,所以script標(biāo)簽放在首屏范圍內(nèi)的HTML代碼段里會(huì)可能影響首屏的內(nèi)容。
  • 普通script標(biāo)簽放在body底部,做與不做async或者defer處理,都不會(huì)影響首屏?xí)r間,但影響DomContentLoad和load的時(shí)間,進(jìn)而影響依賴他們的代碼的執(zhí)行的開(kāi)始時(shí)間。

三、問(wèn)題的答案

回到前面的問(wèn)題:

script標(biāo)簽的位置會(huì)影響首屏?xí)r間么?

答案是:不影響但有可能截?cái)嗍灼恋膬?nèi)容,使其只顯示上面一部分

四、再進(jìn)一步

所以,總算弄清楚這個(gè)眾所周知的常識(shí)了。但設(shè)計(jì)開(kāi)發(fā)中可能會(huì)遇到難以把所有的js放到頁(yè)面最底部的情形。比如:你的頁(yè)面是分模塊來(lái)寫(xiě)的,每一個(gè)模塊都有自己的html、js甚至css,當(dāng)把這些模塊湊到一個(gè)頁(yè)面中的時(shí)候就會(huì)出現(xiàn)js自然而然地出現(xiàn)在HTML中間部分。

我們也遇到了這樣的問(wèn)題,所以就做了一個(gè)開(kāi)源項(xiàng)目:?Tiny-Loader?—— A small loader that load CSS/JS in best way for page performance 簡(jiǎn)單好用。

回答下題目中所提到的問(wèn)題,JS一定要放在Body的最底部么? 如果用了Tiny-Loader,JS可以不放在Body最底部。

轉(zhuǎn)載于:https://www.cnblogs.com/xuyuanjia/p/5717071.html

總結(jié)

以上是生活随笔為你收集整理的JS一定要放在Body的最底部么?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。