瀏覽器渲染與加載機(jī)制

<script>標(biāo)簽可以放在html文件中的任何位置畴椰,但一般放在head或body標(biāo)簽里面滑臊。上次在視頻中聽老師講到最后放入head標(biāo)簽中蚪拦,避免頁面出現(xiàn)抖屏現(xiàn)象牍疏,所以決定深入了解一下瀏覽器的渲染和加載機(jī)制蠢笋。


<script>標(biāo)簽位置

1. 放在<head>里

<head>標(biāo)簽僅次于<title>標(biāo)簽,放在<head>中則此js代碼會在整個網(wǎng)頁最開始解析時就加載執(zhí)行鳞陨,然后依次向下解析渲染昨寞。

注意:進(jìn)行頁面顯示初始化的js必須放在head里面


2. 放在<body>里

瀏覽器按照頁面標(biāo)簽的順序依次解析,在讀取到j(luò)s代碼時會執(zhí)行js語句。

注意:對于通過事件調(diào)用的JS函數(shù)援岩,具體放在頁面的哪個位置并不影響其發(fā)揮作用的時間歼狼,因此,考慮到前端性能方面的問題享怀,可以把不是最先執(zhí)行的和事件調(diào)用的JS代碼放在body的最下面羽峰。


瀏覽器加載和渲染的順序

  • IE下載的順序從上到下,渲染順序也是從上到下凹蜈,下載和渲染同時進(jìn)行。
  • 在渲染到頁面的某一部分時忍啸,其上面的所有部分都已經(jīng)下載完成(并不是說所有相關(guān)聯(lián)的元素都已經(jīng)下載完)仰坦。
  • 如果遇到語義解釋性的標(biāo)簽嵌入文件(JS腳本,CSS樣式)计雌,那么此時IE的下載過程會啟用單獨(dú)連接進(jìn)行下載悄晃。
  • 樣式表在下載完成后,將和以前下載的所有樣式表一起進(jìn)行解析凿滤,解析完成后妈橄,將對此前所有元素(含以前已經(jīng)渲染的)重新進(jìn)行渲染。(也就是上面說的可能出現(xiàn)抖屏現(xiàn)象
  • JS翁脆、CSS中如有重定義眷蚓,后定義函數(shù)將覆蓋前定義函數(shù)。

JS的加載

  • 不能并行下載和解析(阻塞下載)反番。
  • 當(dāng)引用了JS的時候沙热,瀏覽器發(fā)送1個js request就會一直等待該request的返回。因?yàn)闉g覽器需要1個穩(wěn)定的DOM樹結(jié)構(gòu)罢缸,而JS中很有可能有代碼直接改變了DOM樹結(jié)構(gòu)篙贸,比如使用document.write或apppendChild,甚至是直接使用location.href進(jìn)行跳轉(zhuǎn),瀏覽器為了防止出現(xiàn)JS修改DOM樹枫疆,需要重新構(gòu)建DOM樹的情況爵川,所以 就會阻塞其他的下載和呈現(xiàn)

加快HTML頁面加載速度

  1. 頁面減肥:
    a. 頁面的肥瘦是影響加載速度最重要的因素。
    b. 刪除不必要的空格息楔、注釋寝贡。
    c. 將inline的script和css移到外部文件。
    d. 可以使用HTML Tidy來給HTML減肥值依,還可以使用一些壓縮工具來給JavaScript減肥兔甘。

  2. 減少文件數(shù)量:
    a. 減少頁面上引用的文件數(shù)量可以減少HTTP連接數(shù)。
    b. 許多JavaScript鳞滨、CSS文件可以合并最好合并洞焙,人家財幫子都把自己的JavaScript. functions和Prototype.js合并到一個base.js文件里去了。

  3. 減少域名查詢:
    a. DNS查詢和解析域名也是消耗時間的,所以要減少對外部JavaScript澡匪、CSS熔任、圖片等資源的引用,不同域名的使用越少越好唁情。

  4. 緩存重用數(shù)據(jù):
    a. 對重復(fù)使用的數(shù)據(jù)進(jìn)行緩存疑苔。

  5. 優(yōu)化頁面元素加載順序:
    a. 首先加載頁面最初顯示的內(nèi)容和與之相關(guān)的JavaScript和CSS,然后加載HTML相關(guān)的東西甸鸟,像什么不是最初顯示相關(guān)的圖片惦费、flash、視頻等很肥的資源就最后加載抢韭。

  6. 減少inline JavaScript的數(shù)量:
    a. 瀏覽器parser會假設(shè)inline JavaScript會改變頁面結(jié)構(gòu)薪贫,所以使用inline JavaScript開銷較大。
    b. 不要使用document.write()這種輸出內(nèi)容的方法刻恭,使用現(xiàn)代W3C DOM方法來為現(xiàn)代瀏覽器處理頁面內(nèi)容瞧省。

  7. 使用現(xiàn)代CSS和合法的標(biāo)簽:
    a. 使用現(xiàn)代CSS來減少標(biāo)簽和圖像,例如使用現(xiàn)代CSS+文字完全可以替代一些只有文字的圖片鳍贾。
    b. 使用合法的標(biāo)簽避免瀏覽器解析HTML時做“error correction”等操作鞍匾,還可以被HTML Tidy來給HTML減肥。

  8. Chunk your content:
    a. 不要使用嵌套table骑科,而使用非嵌套table或者div橡淑。將基于大塊嵌套的table的layout分解成多個小table,這樣就不需要等到整個頁面(或大table)內(nèi)容全部加載完才顯示咆爽。

  9. 指定圖像和table的大惺崧搿:
    a. 如果瀏覽器可以立即決定圖像或table的大小,那么它就可以馬上顯示頁面而不要重新做一些布局安排的工作伍掀。
    b. 這不僅加快了頁面的顯示掰茶,也預(yù)防了頁面完成加載后布局的一些不當(dāng)?shù)母淖儭?br> c. image使用height和width。


HTML頁面加載和解析流程

  1. 用戶輸入網(wǎng)址(假設(shè)是個html頁面蜜笤,并且是第一次訪問)濒蒋,瀏覽器向服務(wù)器發(fā)出請求,服務(wù)器返回html文件把兔。

  2. 瀏覽器開始載入html代碼沪伙,發(fā)現(xiàn)<head>標(biāo)簽內(nèi)有一個<link>標(biāo)簽引用外部CSS文件。

  3. 瀏覽器又發(fā)出CSS文件的請求县好,服務(wù)器返回這個CSS文件围橡。

  4. 瀏覽器繼續(xù)載入html中<body>部分的代碼,并且CSS文件已經(jīng)拿到手了缕贡,可以開始渲染頁面了翁授。

  5. 瀏覽器在代碼中發(fā)現(xiàn)一個<img>標(biāo)簽引用了一張圖片拣播,向服務(wù)器發(fā)出請求。此時瀏覽器不會等到圖片下載完收擦,而是繼續(xù)渲染后面的代碼贮配。

  6. 服務(wù)器返回圖片文件,由于圖片占用了一定面積塞赂,影響了后面段落的排布泪勒,因此瀏覽器需要回過頭來重新渲染這部分代碼。

  7. 瀏覽器發(fā)現(xiàn)了一個包含一行Javascript代碼的<script>標(biāo)簽宴猾,趕快運(yùn)行它圆存。

  8. Javascript腳本執(zhí)行了這條語句,它命令瀏覽器隱藏掉代碼中的某個<style>(style.display=”none”)仇哆。杯具啊沦辙,突然就少了這么一個元素,瀏覽器不得不重新渲染這部分代碼税产。

  9. 終于等到了</html>的到來怕轿,瀏覽器淚流滿面……

  10. 等等偷崩,還沒完辟拷,用戶點(diǎn)了一下界面中的“換膚”按鈕,Javascript讓瀏覽器換了一下<link>標(biāo)簽的CSS路徑阐斜。

  11. 瀏覽器召集了在座的各位<div><span><ul><li>們衫冻,“大伙兒收拾收拾行李,咱得重新來過……”谒出,瀏覽器向服務(wù)器請求了新的CSS文件隅俘,重新渲染頁面。


  • 問題1
    加載過程中遇到外部css文件笤喳,瀏覽器另外發(fā)出一個請求为居,來獲取css文件。遇到圖片資源杀狡,瀏覽器也會另外發(fā)出一個請求蒙畴,來獲取圖片資源。這是異步請求呜象,并不會影響html文檔進(jìn)行加載膳凝,但是當(dāng)文檔加載過程中遇到j(luò)s文件,html文檔會掛起渲染(加載解析渲染同步)的線程恭陡,不僅要等待文檔中js文件加載完畢蹬音,還要等待解析執(zhí)行完畢,才可以恢復(fù)html文檔的渲染線程休玩。
  • 原因:
    JS有可能會修改DOM著淆,最為經(jīng)典的document.write劫狠,這意味著,在JS執(zhí)行完成前牧抽,后續(xù)所有資源的下載可能是沒有必要的嘉熊,這是js阻塞后續(xù)資源下載的根本原因。
  • 辦法:
    可以將外部引用的js文件放在</body>前扬舒。

  • 問題:
    雖然css文件的加載不影響js文件的加載阐肤,但是卻影響js文件的執(zhí)行,即使js文件內(nèi)只有一行代碼讲坎,也會造成阻塞孕惜。
  • 原因:
    可能會有 var width = $('#id').width(),這意味著晨炕,js代碼執(zhí)行前衫画,瀏覽器必須保證css文件已下載和解析完成。這也是css阻塞后續(xù)js的根本原因瓮栗。
  • 辦法:
    當(dāng)js文件不需要依賴css文件時削罩,可以將js文件放在頭部css的前面。

  • 注意:
    不要在外部調(diào)用的js文件中調(diào)用運(yùn)行時間較長的函數(shù)费奸,如果一定要用弥激,可以使用setTimeout函數(shù)。
  • 原因:
    瀏覽器有以上五個常駐線程
    -- 瀏覽器GUI渲染線程
    -- javascript引擎線程
    -- 瀏覽器定時器觸發(fā)線程(setTimeout)
    -- 瀏覽器事件觸發(fā)線程
    -- 瀏覽器http異步請求線程(.jpg <link />這類請求)
    由于 javascript引擎線程為單線程愿阐,當(dāng)js引擎線程(第二個)進(jìn)行時微服,會掛起其他一切線程,所以代碼都是先壓到隊(duì)列缨历,采用先進(jìn)先出的方式運(yùn)行以蕴,這個時候3、4辛孵、5這三類線線程也會產(chǎn)生不同的異步事件丛肮。

預(yù)加載

  • 現(xiàn)代瀏覽器存在 prefetch 優(yōu)化,瀏覽器會另外開啟線程魄缚,提前下載js宝与、css文件,需要注意的是鲜滩,預(yù)加載js并不會改變dom結(jié)構(gòu)伴鳖,他將這個工作留給主加載。

  • 預(yù)加載網(wǎng)頁徙硅,利用空余時間來提前加載該網(wǎng)頁的后續(xù)網(wǎng)頁

<link rel="prefetch" href="http://">

為js腳本添加defer屬性榜聂,使得瀏覽器不等js腳本加載執(zhí)行完,就加載后面的圖片

<script defer="true" src="JavaScript.js" type="text/javascript"/>

解析

  1. DOM樹構(gòu)建過程是深度遍歷過程嗓蘑,當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)都構(gòu)建好后才會去構(gòu)建當(dāng)前節(jié)點(diǎn)的下一個兄弟節(jié)點(diǎn)须肆。

2 . 將CSS解析成 CSS Rule Tree 匿乃。

  1. 根據(jù)DOM樹和CSSOM來構(gòu)造 Rendering Tree。注意:Rendering Tree 渲染樹并不等同于 DOM 樹豌汇,因?yàn)橐恍┫?Header 或 display:none 的東西就沒必要放在渲染樹中了幢炸。

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

  3. 再下一步就是繪制闸天,即遍歷render樹,并使用UI后端層繪制每個節(jié)點(diǎn)斜做。


    image.png

上述這個過程是逐步完成的苞氮,為了更好的用戶體驗(yàn),渲染引擎將會盡可能早的將內(nèi)容呈現(xiàn)到屏幕上瓤逼,并不會等到所有的html都解析完成之后再去構(gòu)建和布局render樹笼吟。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容,同時霸旗,可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容贷帮。


Reflow(回流):

瀏覽器要花時間去渲染,當(dāng)它發(fā)現(xiàn)了某個部分發(fā)生了變化影響了布局定硝,那就需要倒回去重新渲染皿桑。

Repaint(重繪):

如果只是改變了某個元素的背景顏色毫目,文字顏色等蔬啡,不影響元素周圍或內(nèi)部布局的屬性,將只會引起瀏覽器的repaint镀虐,重畫某一部分箱蟆。

Reflow要比Repaint更花費(fèi)時間,也就更影響性能刮便。所以在寫代碼的時候空猜,要盡量避免過多的Reflow。


引起reflow的原因

  • 頁面初始化
  • 某些元素的尺寸變了
  • 某些CSS的屬性發(fā)生變化了恨旱,如display:none
  • 操作DOM時辈毯,如添加子節(jié)點(diǎn)

減少 reflow/repaint

  • 不要一條一條地修改 DOM 的樣式。與其這樣搜贤,還不如預(yù)先定義好 css 的 class谆沃,然后修改 DOM 的 className。
  • 要把 DOM 結(jié)點(diǎn)的屬性值放在一個循環(huán)里當(dāng)成循環(huán)里的變量仪芒。
  • 為動畫的 HTML 元件使用 fixed 或 absoult 的 position唁影,那么修改他們的 CSS 是不會 reflow 的耕陷。
  • 千萬不要使用 table 布局。因?yàn)榭赡芎苄〉囊粋€小改動會造成整個 table 的重新布局

CSS規(guī)范

CSS選擇符是從右到左進(jìn)行匹配的据沈。從右到左哟沫!所以,#nav li 我們以為這是一條很簡單的規(guī)則锌介,秒秒鐘就能匹配到想要的元素嗜诀,但是,但是孔祸,但是裹虫,是從右往左匹配啊,所以融击,會去找所有的li筑公,然后再去確定它的父元素是不是#nav。尊浪,因此匣屡,寫css的時候需要注意:

  • dom深度盡量淺。
  • 減少inline javascript拇涤、css的數(shù)量捣作。
  • 使用現(xiàn)代合法的css屬性。
  • 不要為id選擇器指定類名或是標(biāo)簽鹅士,因?yàn)閕d可以唯一確定一個元素券躁。
  • 避免后代選擇符,盡量使用子選擇符掉盅。原因:子元素匹配符的概率要大于后代元素匹配符也拜。-后代選擇符;#tp p{} 子選擇符:#tp>p{}
  • 避免使用通配符,舉一個例子趾痘,.mod .hd *{font-size:14px;} 根據(jù)匹配順序,將首先匹配通配符,也就是說先匹配出通配符,然后匹配.hd(就是要對dom樹上的所有節(jié)點(diǎn)進(jìn)行遍歷他的父級元素),然后匹配.mod,這樣的性能耗費(fèi)可想而知.

總結(jié)

  1. JS的下載和執(zhí)行會阻塞DOM樹的構(gòu)建以及其它資源的下載慢哈。原因是瀏覽器需要一個穩(wěn)定的DOM樹結(jié)構(gòu) ,來防止JS修改DOM樹永票,導(dǎo)致需要重新構(gòu)建DOM樹的情況
  2. JS載入后馬上執(zhí)行卵贱,如果JS代碼中有執(zhí)行時間長的函數(shù),用SetTimeOut()
  3. CSS文件的加載雖不影響JS文件的加載侣集,但卻可能影響到JS文件的執(zhí)行造成阻塞键俱。因此必須保證CSS文件已下載和解析完成。
    4.關(guān)于順序的問題世分,可以將CSS文件在最前面加載编振,再載入JS。并且對于事件調(diào)用型js代碼可以放到<body>標(biāo)簽的最末端 罚攀。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末党觅,一起剝皮案震驚了整個濱河市雌澄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杯瞻,老刑警劉巖镐牺,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異魁莉,居然都是意外死亡睬涧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門旗唁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畦浓,“玉大人,你說我怎么就攤上這事检疫⊙惹耄” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵屎媳,是天一觀的道長夺溢。 經(jīng)常有香客問我,道長烛谊,這世上最難降的妖魔是什么风响? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮丹禀,結(jié)果婚禮上状勤,老公的妹妹穿的比我還像新娘。我一直安慰自己双泪,他們只是感情好持搜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著攒读,像睡著了一般朵诫。 火紅的嫁衣襯著肌膚如雪辛友。 梳的紋絲不亂的頭發(fā)上薄扁,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音废累,去河邊找鬼邓梅。 笑死础钠,一個胖子當(dāng)著我的面吹牛阿弃,可吹牛的內(nèi)容都是我干的匿值。 我是一名探鬼主播侯养,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼床三,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了疏旨?” 一聲冷哼從身側(cè)響起上荡,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毅待,沒想到半個月后尚卫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡尸红,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年吱涉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片外里。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡怎爵,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出盅蝗,到底是詐尸還是另有隱情鳖链,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布墩莫,位于F島的核電站撒轮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏贼穆。R本人自食惡果不足惜题山,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望故痊。 院中可真熱鬧顶瞳,春花似錦、人聲如沸愕秫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽戴甩。三九已至符喝,卻和暖如春甜孤,著一層夾襖步出監(jiān)牢的瞬間缴川,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工嘹狞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親隅肥。 傳聞我的和親對象是個殘疾皇子绿语,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5聚请? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 27,486評論 1 45
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 13,753評論 1 92
  • 大家都知道萬維網(wǎng)的應(yīng)用層使用了HTTP協(xié)議蒋失,并且用瀏覽器作為入口訪問網(wǎng)絡(luò)上的資源。用戶在使用瀏覽器訪問一個網(wǎng)站時需...
    SylvanasSun閱讀 2,149評論 1 12
  • (注1:如果有問題歡迎留言探討桐玻,一起學(xué)習(xí)篙挽!轉(zhuǎn)載請注明出處,喜歡可以點(diǎn)個贊哦D餮ァ)(注2:更多內(nèi)容請查看我的目錄[ht...
    love丁酥酥閱讀 1,478評論 0 4
  • 轉(zhuǎn)載 前言 見解有限偏竟,如有描述不當(dāng)之處煮落,請幫忙及時指出,如有錯誤踊谋,會及時修正蝉仇。 ----------超長文+多圖預(yù)...
    程序員之路閱讀 1,122評論 3 21