摘要:前端渲染過程的二三事本文不會介紹整個前端渲染過程的步驟,只是記錄最近閱讀的文章的些許思考和感悟。那么現(xiàn)在我們可以明白這個問題的關(guān)鍵所在了,因?yàn)樵诖蟛糠猪撁嬷惺菗碛械模捎谄浣馕鲰樞颍敲丛谑录氨囟ㄒ呀?jīng)成功構(gòu)造樹。
前端渲染過程的二三事
本文不會介紹整個前端渲染過程的步驟,只是記錄最近閱讀的文章的些許思考和感悟。(文章地址一(系列),文章地址二)
希望大家在閱讀這篇文章之前能將上述文章仔細(xì)瀏覽一篇,因?yàn)楸疚乃龌臼腔谄鋬?nèi)容。
Navigation Timing API和瀏覽器加載事件Navigation Timing API:可通過打印(performance)查看;
瀏覽器加載事件:domContentLoaded,onload
上圖整理了Navigation Timing API中的一些事件和瀏覽器加載事件的發(fā)生順序。
這些事件的含義是什么呢?我們直接引用文章地址一(系列)的介紹:
domLoading:這是整個過程的起始時間戳,瀏覽器即將開始解析第一批收到的 HTML 文檔字節(jié)。
domInteractive:表示瀏覽器完成對所有 HTML 的解析并且 DOM 構(gòu)建完成的時間點(diǎn)。
domContentLoaded:表示 DOM 準(zhǔn)備就緒并且沒有樣式表阻止 JavaScript 執(zhí)行的時間點(diǎn),這意味著現(xiàn)在我們可以構(gòu)建渲染樹了。
許多 JavaScript 框架都會等待此事件發(fā)生后,才開始執(zhí)行它們自己的邏輯。因此,瀏覽器會捕獲 EventStart 和 EventEnd 時間戳,讓我們能夠追蹤執(zhí)行所花費(fèi)的時間。
domComplete:顧名思義,所有處理完成,并且網(wǎng)頁上的所有資源(圖像等)都已下載完畢,也就是說,加載轉(zhuǎn)環(huán)已停止旋轉(zhuǎn)。
loadEvent:作為每個網(wǎng)頁加載的最后一步,瀏覽器會觸發(fā) onload 事件,以便觸發(fā)額外的應(yīng)用邏輯。
看了上述事件的介紹,大致了解了每個事件所代表的含義,但也帶著少許疑惑:
HTML解析是分批進(jìn)行的嗎?為什么要分批進(jìn)行?
domContentLoaded事件結(jié)束后可以構(gòu)建渲染樹了,是否意味著CSSOM樹構(gòu)建也在該事件之前就已完成?
domContentLoaded事件表示DOM準(zhǔn)備就緒并且沒有樣式表阻止 JavaScript執(zhí)行的時間點(diǎn),可是JavaScript執(zhí)行是在構(gòu)建DOM樹之前,那這是不是意味著該事件在DOM樹構(gòu)建完成后就執(zhí)行了?若是這與domInteractive事件有什么區(qū)別呢?
首先看第一個問題,我們直接用chrome控制臺的performance來看效果。
上圖中,上方的Network的藍(lán)條是HTML的下載時間,下方箭頭所指是HTML的解析時間。
從中我們可以得出HTML解析的確是分批進(jìn)行,并且解析并不需要等HTML完全下載完。那為什么要分批進(jìn)行呢?這個問題我找了許多資料也沒有得出結(jié)論,于是自己從中思考。假設(shè)不是分批進(jìn)行,那實(shí)現(xiàn)會有兩種情況:1.等HTML全部下載完,再一起解析;2.每下載一定量的HTML就將其放入解析器等待排隊解析。前者首先肯定被排除,若HTML很大,會影響首屏加載速度,后者按理速度更快,或許其實(shí)現(xiàn)的難度以及可能會帶來的一些問題而沒有采用?這個問題思考了良久,感覺從理論上是可行的,但從技術(shù)角度,由于自己這方面的知識實(shí)在薄弱,所以也無法得知其實(shí)現(xiàn)的過程是否存在技術(shù)瓶頸。
第二個問題:CSSOM樹構(gòu)建是否在domContentLoaded事件之前?
話不多說我們自己實(shí)踐。
首先我先創(chuàng)建一個HTML文件并寫入少許標(biāo)簽,再創(chuàng)建一個CSS并于HTML引入,在CSS文件中寫入大量內(nèi)容(自己實(shí)踐時寫了5W多行)。然后用performance查看。
上圖每個箭頭代表的含義:
HTML解析結(jié)束時間
domContentLoaded加載時間
CSS文件下載完的時間
CSS文件解析的時間
從這個步驟以及其所處時間,我們可以清晰的得出,該結(jié)論不準(zhǔn)確。那么該作者為什么會得出該結(jié)論呢,是他犯錯了嗎?我隨后發(fā)現(xiàn)他在這篇文章下面還寫了一句“domContentLoaded一般表示DOM和CSSOM均準(zhǔn)備就緒的時間點(diǎn)”。那么這句話意味著大部分的時候CSSOM樹的構(gòu)建是在domContentLoaded事件之前。可是這個大部分又指的是什么情況,這又涉及到另一個知識點(diǎn)“DOM樹,CSSOM樹,JS的三角關(guān)系”,構(gòu)造DOM樹時遇見JS會先解析執(zhí)行JS,而在解析執(zhí)行JS時遇到CSSOM,又會先構(gòu)造CSSOM樹,這個過程稍后會具體說明。那么現(xiàn)在我們可以明白這個問題的關(guān)鍵所在了,因?yàn)樵诖蟛糠猪撁嬷惺菗碛蠮S的,而由于其解析順序,那么在domContentLoaded事件之前必定已經(jīng)成功構(gòu)造CSSOM樹。
第三個問題:domInteractive與domContentLoaded的區(qū)別是什么呢?這兩個事件中間是否還會進(jìn)行其他操作?
我們都知道script標(biāo)簽有defer和async兩個屬性。有了這兩個屬性,瀏覽器就會加一個進(jìn)程下載JS。那么下載完的執(zhí)行時間點(diǎn)是在什么時候?其中async會在JS下載完后立馬執(zhí)行,也正是這個原因,會導(dǎo)致JS的執(zhí)行順序不一定按標(biāo)簽的從上至下,而是按照下載完的時間。那么defer屬性的執(zhí)行時間呢,我想大家應(yīng)該都能猜到了,它的執(zhí)行時間點(diǎn)的確就是在上述的兩個事件之間,那么我們也就得知這兩個事件的區(qū)別所在。
三大樹我們都知道前端渲染有三大樹:DOM樹,CSSOM樹,RENDER樹。那么這三大樹的構(gòu)造時間和上述的事件執(zhí)行時間的順序又是怎樣的呢。
其中DOM樹和RENDER樹所在位置其實(shí)是顯而易見的,并且在之前內(nèi)容也已經(jīng)指出。DOM樹在domInteractive事件之前,RENDER樹在domContentLoaded事件之后。但是CSSOM樹就難以捉摸,其與DOM樹的關(guān)系,完全受到是否擁有JS影響。
在確定CSSOM樹所處位置前,我們先確定一個上面提到的概念:構(gòu)造DOM樹時遇見JS會先解析執(zhí)行JS,而在解析執(zhí)行JS時遇到CSSOM,又會先構(gòu)造CSSOM樹。官方給出的原因是,JS會使用document.write而改變DOM樹,所以構(gòu)造DOM樹時碰到JS會先執(zhí)行JS;而JS在執(zhí)行時,需要查找CSS,所以執(zhí)行JS時,碰到構(gòu)造CSSOM樹,會先構(gòu)造CSSOM樹。但是這里有一點(diǎn)奇怪的時,JS也可以通過創(chuàng)造Link標(biāo)簽的方式改變CSSOM樹,所以個人感覺官方的這種解釋有點(diǎn)牽強(qiáng)。不過官方的解釋雖然不能讓人完全信服,但這執(zhí)行順序是不會有錯的。
接下來我們分別通過有無JS兩大類確認(rèn)CSSOM樹所處位置:
無JS的情況
由于DOM樹和CSSOM樹是并行解析的情況,所以這兩個樹構(gòu)建完成的順序完全無法固定,只由它們自己本身大小有關(guān)。因此CSSOM樹構(gòu)建完成的時間既可能在domInteractive之前,可能在domContentLoaded之后,也可能在這兩事件之間。
有JS的情況
這里我們先假設(shè)CSS文件很小,在沒還解析到JS時就已完成解析,那么這種情況其實(shí)必定發(fā)生在domInteractive之前,因?yàn)槎歼€沒解析到JS,說明DOM樹必定沒有構(gòu)建完成。那么再假設(shè)CSS文件很大,然后中途遇到JS文件,這時候JS文件發(fā)現(xiàn)在構(gòu)造CSSOM樹,其就會等待CSSOM樹構(gòu)建完成后再解析執(zhí)行JS,所以這種情況CSSOM也必定在domInteractive之前。
但是有2個有意思的情況:
(1) 如果我們動態(tài)創(chuàng)建link標(biāo)簽并添加到html中,那么又會發(fā)生什么呢?若JS還沒解析執(zhí)行完,那么會停止JS而去解析CSS,若JS已執(zhí)行完那么CSSOM樹其實(shí)也不是必定在domInteractive之前。(當(dāng)然這可能已經(jīng)不算初次渲染構(gòu)建)
(2) link標(biāo)簽放到JS后面又會發(fā)生什么呢?這種情況我發(fā)現(xiàn)不管我怎么嘗試,CSSOM樹必定在DOM樹構(gòu)建之前構(gòu)建,但其又在JS執(zhí)行完成后。如果有興趣的同學(xué)可以查查是為什么。
其實(shí)前端渲染是一個很龐大的知識點(diǎn),并且其涉及的周邊知識也及其龐大,本文只是對其中一個小知識點(diǎn)做了思考和實(shí)踐。最后要說的一點(diǎn)是,以上內(nèi)容,純屬個人見解,如有不當(dāng),請多指教。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/99186.html
摘要:常用的數(shù)組方法刪除數(shù)組的最后一個元素,返回被刪除的元素,原數(shù)組長度減。原數(shù)組發(fā)生了變化,但沒有創(chuàng)建新的數(shù)組。將指定數(shù)組進(jìn)行排序,返回排好序的數(shù)組。顛倒數(shù)組元素的順序,返回逆序后的數(shù)組。 數(shù)組,對于每一個前端人員來說是非常常見且重要的數(shù)據(jù)結(jié)構(gòu)之一,也是面試常常出現(xiàn)的題目,掌握數(shù)組的方法能幫助我們更高效地處理問題。不過在數(shù)組的學(xué)習(xí)中,我們常常會混淆數(shù)組本身的方法和Javascript提供的...
摘要:傳統(tǒng)的網(wǎng)頁編程采用的三劍客來實(shí)現(xiàn),在微信小程序中同樣有三劍客。觀察者模式不難實(shí)現(xiàn),重點(diǎn)是如何在微信小程序中搭配其特有的生命周期來使用。交互事件傳統(tǒng)的事件傳遞類型有冒泡型與捕獲型,微信小程序中自然也有。 本文由作者鄒永勝授權(quán)網(wǎng)易云社區(qū)發(fā)布。 簡介為了更好的展示我們即時通訊SDK強(qiáng)悍的能力,網(wǎng)易云信IM SDK微信小程序DEMO的開發(fā)就提上了日程。用產(chǎn)品的話說就是: 云信 IM 小程序 S...
摘要:但對于整個事件流上的別的元素來說,執(zhí)行順序還會受到另外一個因素的影響。以上面的場景為例,在捕獲階段執(zhí)行的事件,如果執(zhí)行,則事件流終止,不會到達(dá)目標(biāo)階段,的世界則不會被執(zhí)行執(zhí)行結(jié)果為線上參考事件流 向dom綁定事件的事件的三種方式 行內(nèi)綁定 按鈕 js內(nèi)綁定 btnDom.onclick = function clickHandler() { console.log(click)...
摘要:分表字段的選擇。問題產(chǎn)生之前提到在分表應(yīng)用上線前我們需要將原有表的數(shù)據(jù)遷移到新表中,這樣才能保證業(yè)務(wù)不受影響。雖說凌晨的業(yè)務(wù)量下降,但依然有少部分的請求過來,也會出現(xiàn)各種數(shù)據(jù)庫異常。 showImg(https://segmentfault.com/img/remote/1460000019462791?w=496&h=285); 前言 本篇是上一篇《一次分表踩坑實(shí)踐的探討》,所以還沒...
閱讀 3205·2023-04-26 01:39
閱讀 3358·2023-04-25 18:09
閱讀 1627·2021-10-08 10:05
閱讀 3241·2021-09-22 15:45
閱讀 2794·2019-08-30 15:55
閱讀 2402·2019-08-30 15:54
閱讀 3174·2019-08-30 15:53
閱讀 1336·2019-08-29 12:32