進階任務1(主線任務):JS相關概念

任務

  1. CSS和JS在網頁中的放置順序是怎樣的爷绘?
  2. 解釋白屏和FOUC
  3. async和defer的作用是什么耿眉?有什么區(qū)別
  4. 簡述網頁的渲染機制
  5. 從上面4個題目中隨機選擇一題寫成博客,投遞到饑人谷技術博客66 (可選題目)
1.CSS和JS在網頁中的放置順序是怎樣的

css樣式放在head中。
js放置在body標簽內的最后,script標簽內吁系。外鏈用<script src=""></script>德召,內部的用<script></script>

2.白屏問題

對于圖片和CSS, 在加載時會并發(fā)加載(如一個域名下同時加載兩個文件). 但在加載 JavaScript 時,會禁用并發(fā),并且阻止其他內容的下載. 所以把 JavaScript 放入頁面頂部也會導致 白屏 現(xiàn)象.

FOUC (Flash of Unstyled Content) 無樣式內容閃爍

如果把樣式放在底部,對于IE瀏覽器,在某些場景下(點擊鏈接,輸入URL,使用書簽進入等),會出現(xiàn) FOUC 現(xiàn)象(逐步加載無樣式的內容,等CSS加載后頁面突然展現(xiàn)樣式).對于 Firefox 會一直表現(xiàn)出 FOUC .
將JS放在底部

  • 腳本會阻塞后面內容的呈現(xiàn)
  • 腳本會阻塞其后組件的下載
    對于圖片和CSS, 在加載時會并發(fā)加載(如一個域名下同時加載兩個文件). 但在加載JavaScript時,會禁用并發(fā),并且阻止其他內容的下載. 所以把JavaScript放入頁面頂部也會導致白屏現(xiàn)象。
3.async和defer的作用是什么汽纤?有什么區(qū)別

加載異步

<script src="script.js"></script>

沒有 defer 或 async上岗,瀏覽器會立即加載并執(zhí)行指定的腳本,“立即”指的是在渲染該 script 標簽之下的文檔元素之前蕴坪,也就是說不等待后續(xù)載入的文檔元素肴掷,讀到就加載并執(zhí)行。

<script async src="script.js"></script>

有 async背传,加載和渲染后續(xù)文檔元素的過程將和 script.js 的加載與執(zhí)行并行進行(異步)呆瞻。

<script defer src="script.js"></script>

有 defer,加載后續(xù)文檔元素的過程將和 script.js 的加載并行進行(異步)径玖,但 script.js 的執(zhí)行要在所有元素解析完成之后痴脾,DOMContentLoaded 事件觸發(fā)之前完成。
defer:腳本延遲到文檔解析和顯示后執(zhí)行梳星,有順序
async:不保證順序

簡述網頁的渲染機制

解析 HTML 標簽, 構建 DOM 樹
解析 CSS 標簽, 構建 CSSOM 樹
把 DOM 和 CSSOM 組合成 渲染樹 (render tree)
在渲染樹的基礎上進行布局, 計算每個節(jié)點的幾何結構
把每個節(jié)點繪制到屏幕上 (painting)

render-tree-construction.png

瀏覽器的渲染機制

Google Web Fundamentals 是一個非常優(yōu)秀的文檔赞赖,里面講到了跟web、瀏覽器冤灾、前端的方方面面前域。我總結一下其中的 Ilya Grigorik 寫的 Critical rendering path 瀏覽器渲染機制部分的內容如下:
幾個概念

1、DOM:Document Object Model韵吨,瀏覽器將HTML解析成樹形的數(shù)據結構话侄,簡稱DOM。

2学赛、CSSOM:CSS Object Model年堆,瀏覽器將CSS代碼解析成樹形的數(shù)據結構抵栈。

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

DOM 樹的構建過程是一個深度遍歷過程:當前節(jié)點的所有子節(jié)點都構建好后才會去構建當前節(jié)點的下一個兄弟節(jié)點矮锈。

4手幢、Render Tree:DOM 和 CSSOM 合并后生成 Render Tree没酣,如下圖:

Render Tree 和DOM一樣拱雏,以多叉樹的形式保存了每個節(jié)點的css屬性贪惹、節(jié)點本身屬性滴劲、以及節(jié)點的孩子節(jié)點攻晒。

注意:display:none 的節(jié)點不會被加入 Render Tree,而 visibility: hidden 則會班挖,所以鲁捏,如果某個節(jié)點最開始是不顯示的,設為 display:none 是更優(yōu)的萧芙。(具體可以看這里)
瀏覽器的渲染過程

Create/Update DOM And request css/image/js:瀏覽器請求到HTML代碼后给梅,在生成DOM的最開始階段(應該是 Bytes → characters 后)假丧,并行發(fā)起css、圖片动羽、js的請求包帚,無論他們是否在HEAD里。
注意:發(fā)起 js 文件的下載 request 并不需要 DOM 處理到那個 script 節(jié)點运吓,比如:簡單的正則匹配就能做到這一點渴邦,雖然實際上并不一定是通過正則:)。這是很多人在理解渲染機制的時候存在的誤區(qū)拘哨。

Create/Update Render CSSOM:CSS文件下載完成几莽,開始構建CSSOM

Create/Update Render Tree:所有CSS文件下載完成,CSSOM構建結束后宅静,和 DOM 一起生成 Render Tree章蚣。

Layout:有了Render Tree,瀏覽器已經能知道網頁中有哪些節(jié)點姨夹、各個節(jié)點的CSS定義以及他們的從屬關系纤垂。下一步操作稱之為Layout,顧名思義就是計算出每個節(jié)點在屏幕中的位置磷账。

Painting:Layout后峭沦,瀏覽器已經知道了哪些節(jié)點要顯示(which nodes are visible)、每個節(jié)點的CSS屬性是什么(their computed styles)逃糟、每個節(jié)點在屏幕中的位置是哪里(geometry)吼鱼。就進入了最后一步:Painting,按照算出來的規(guī)則绰咽,通過顯卡菇肃,把內容畫到屏幕上。

以上五個步驟前3個步驟之所有使用 “Create/Update” 是因為DOM取募、CSSOM琐谤、Render Tree都可能在第一次Painting后又被更新多次,比如JS修改了DOM或者CSS屬性玩敏。

Layout 和 Painting 也會被重復執(zhí)行斗忌,除了DOM、CSSOM更新的原因外旺聚,圖片下載完成后也需要調用Layout 和 Painting來更新網頁织阳。
看 Timeline,一目了然

我扒了一段有贊PC首頁的代碼到本地砰粹,通過Node跑起來唧躲。Node作為Server端,對/js/jquery.js 做了延時2s返回的處理,并且把<script src="http://127.0.0.1:8080/js/jquery.js"></script> 放到導航欄的下面惊窖,結果是這樣的:

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

首屏時間和DomContentLoad事件沒有必然的先后關系

所有CSS盡早加載是減少首屏時間的最關鍵

js的下載和執(zhí)行會阻塞Dom樹的構建(嚴謹?shù)卣f是中斷了Dom樹的更新),所以script標簽放在首屏范圍內的HTML代碼段里會截斷首屏的內容厘贼。

script標簽放在body底部界酒,做與不做async或者defer處理,都不會影響首屏時間嘴秸,但影響DomContentLoad和load的時間毁欣,進而影響依賴他們的代碼的執(zhí)行的開始時間。

三岳掐、問題的答案

回到前面的問題:

script標簽的位置會影響首屏時間么凭疮?

答案是:不影響(如果這里里的首屏指的是頁面從白板變成網頁畫面——也就是第一次Painting),但有可能截斷首屏的內容串述,使其只顯示上面一部分执解。

為什么說是“有可能”呢?纲酗,如果該js下載地比css還快衰腌,或者script標簽不在第一屏的html里,實際上是不影響的觅赊。明白這一影響邊界非常重要右蕊,這樣我們在考察頁面性能瓶頸的時候就有的放矢了。舉個例子:在網頁的第二屏有一個通用模塊吮螺,實際上我們是可以把它的js邏輯獨立成一個文件饶囚,將模塊的html和js標簽放在一起做成獨立的模板引進來的(如果它的js比較小或者說因為多了一個文件會多占用一個TCP連接和帶寬,這實際上是另外一個話題了鸠补,請參考我文章開頭的聲明)萝风。
四、總結紫岩、再進一步

所以闹丐,總算弄清楚這個眾所周知的常識了。我們來總結一下:

如果script標簽的位置不在首屏范圍內被因,不影響首屏時間

所有的script標簽應該放在body底部是很有道理的

但從性能最優(yōu)的角度考慮卿拴,即使在body底部的script標簽也會拖慢首屏出來的速度,因為瀏覽器在最一開始就會請求它對應的js文件梨与,而這堕花,占用了有限的TCP鏈接數(shù)、帶寬甚至運行它所需要的CPU粥鞋。這也是為什么script標簽會有async或defer屬性的原因之一缘挽。

可是,在復雜的實際應用場景中,要貫徹這幾條結論可能會遇到問題壕曼,比如:

你的頁面是分模塊來寫的苏研,每一個模塊都有自己的html、js甚至css腮郊,當把這些模塊湊到一個頁面中的時候就會出現(xiàn)js自然而然地出現(xiàn)在HTML中間部分摹蘑。你很難把script標簽都放到底部

即使你把script標簽都放到底部,但script標簽的存在終究是拖慢了首屏時間轧飞、DomContendLoad和loaded的時間衅鹿。如果只有一個script標簽,我們可以加一個async过咬,但多個async的script標簽的結果會是js文件被亂序執(zhí)行的大渤,這顯然不是我們想要的。

我們也遇到了這樣的問題掸绞,所以就做了一個開源項目:Tiny-Loader —— A small loader that load CSS/JS in best way for page performance 簡單好用泵三。

瀏覽器頁面加載解析渲染機制(一)
JS 一定要放在 Body 的最底部么?聊聊瀏覽器的渲染機制
HankZhuo的技術博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末衔掸,一起剝皮案震驚了整個濱河市切黔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌具篇,老刑警劉巖纬霞,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異驱显,居然都是意外死亡诗芜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門埃疫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伏恐,“玉大人,你說我怎么就攤上這事栓霜〈滂耄” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵胳蛮,是天一觀的道長销凑。 經常有香客問我,道長仅炊,這世上最難降的妖魔是什么斗幼? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮抚垄,結果婚禮上蜕窿,老公的妹妹穿的比我還像新娘谋逻。我一直安慰自己,他們只是感情好桐经,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布毁兆。 她就那樣靜靜地躺著,像睡著了一般阴挣。 火紅的嫁衣襯著肌膚如雪气堕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天屯吊,我揣著相機與錄音送巡,去河邊找鬼摹菠。 笑死盒卸,一個胖子當著我的面吹牛,可吹牛的內容都是我干的次氨。 我是一名探鬼主播蔽介,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼煮寡!你這毒婦竟也來了虹蓄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤幸撕,失蹤者是張志新(化名)和其女友劉穎薇组,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坐儿,經...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡律胀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了貌矿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炭菌。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逛漫,靈堂內的尸體忽然破棺而出黑低,到底是詐尸還是另有隱情,我是刑警寧澤酌毡,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布克握,位于F島的核電站,受9級特大地震影響枷踏,放射性物質發(fā)生泄漏玛荞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一呕寝、第九天 我趴在偏房一處隱蔽的房頂上張望勋眯。 院中可真熱鬧婴梧,春花似錦、人聲如沸客蹋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讶坯。三九已至番电,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間辆琅,已是汗流浹背漱办。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留婉烟,地道東北人娩井。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像似袁,于是被迫代替她去往敵國和親洞辣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內容

  • 1. CSS和JS在網頁中的放置順序是怎樣的昙衅? css放在head標簽內扬霜,防止渲染時出現(xiàn)白屏 js放在最后body...
    billa_8f6b閱讀 574評論 0 0
  • 1. CSS和JS在網頁中的放置順序是怎樣的? CSS最好放入header中而涉,即放在網頁內容(html標簽中包含的...
    熊蛋子17閱讀 505評論 0 0
  • CSS和JS在網頁中的放置順序是怎樣的著瓶? css放到head標簽內 js一般放到body尾部,因為js會涉及dom...
    hhg121閱讀 308評論 0 0
  • 1 . CSS和JS在網頁中的放置順序 CSS要放頭部head中的link標簽內引入啼县。 js文件要放在 標簽中材原,...
    osborne閱讀 305評論 0 0
  • 在windows上建立Agent比較簡單,在linux部署的jenkins連接agent,需要在agent上添加專...
    一個全棧的小白閱讀 1,155評論 0 1