前幾天剛剛學(xué)完css照皆,這兩天開始進(jìn)軍js部分,看了一些老師們的操作視頻沸停,有理論的膜毁,有展示的現(xiàn)象得到的一些結(jié)論的東西,第一遍看起來愤钾,其實很沒有感的瘟滨,因為滿腦子都在引入概念,跟著老師走绰垂,自己其實在被動接受室奏,也不敢自己跟著操作,怕跟不上節(jié)奏了劲装,都怪自己是計算機界的一種小白了胧沫。所以心里發(fā)誓,有必要把c和Java好好下來研究研究了占业。廢話不多說绒怨,我第二遍看視頻,一遍看谦疾,一遍看代碼南蹂,思考,才有了感的念恍。
瀏覽器的渲染機制
其實這個就是理論上的東西六剥,最具有邏輯性了,所有很容易明白峰伙,理解疗疟,就算是拿來主義,也不可恥瞳氓,因為本來就是如此策彤,除非是作為一個瀏覽器開發(fā)者才會以此為恥的吧。
記得學(xué)HTML時,也有一個機制攻略的店诗,那個就是從URL輸入到瀏覽器展示頁面的一個總體的思路過程了裹刮,資料可回顧參考《初學(xué)從url到展示網(wǎng)頁的感官》,這個過程里的其中一部分就是現(xiàn)在要講的瀏覽器渲染機制了庞瘸。當(dāng)時只是總攬全局捧弃,并且在邏輯上明白了一個思路,現(xiàn)在學(xué)到這里恕洲,我們需要細(xì)細(xì)拿出這 其中一部分塔橡,好好地品味下內(nèi)在的想法如何實現(xiàn)的。
具體思路:瀏覽器發(fā)出請求霜第,服務(wù)器收到后,回復(fù)給html文件户辞,瀏覽器接收并解析:解析到css文件泌类,發(fā)請求要css文件;解析到j(luò)s文件底燎,發(fā)請求要js文件刃榨。
html文件在第一時間解析完成,在瀏覽器的邏輯下双仍,生成DOM樹枢希。
同時,接收到css文件后朱沃,解析苞轿,生成cssOM樹,也就是樣式樹逗物。
然后兩棵樹互相聯(lián)系作用搬卒,一個是角色,一個是角色的各種屬性翎卓,搭配起來契邀,形成了一顆渲染樹,這棵樹也是存在于瀏覽器機制的邏輯里的失暴,只是為了讓人更明白坯门,所有,我覺得把這個理念概念化語義化了哦逗扒。
然后瀏覽器通過渲染樹古戴,對各個節(jié)點標(biāo)簽進(jìn)行布局計算,計算完了缴阎,就開始畫畫允瞧,畫好了就顯示成頁面了。
流程圖如下:
其實在這里,我就感到奇怪了述暂,比如js文件呢痹升?還有實際操作的話,這個理論的應(yīng)用層面在瀏覽器上會有什么樣的現(xiàn)象和問題畦韭?這就是我下面想要說的疼蛾,不過我才疏學(xué)淺,時間很緊艺配,只能把一些現(xiàn)象說出來察郁,具體的一些結(jié)論,我能查出根據(jù)的會覺得會好转唉,模凌兩可的只能作為自己的猜想了皮钠。說真的,瀏覽器其實原理一樣赠法,但是耐不住開發(fā)人員的牛脾氣麦轰,所以,原理僅僅是在開發(fā)人員眼里的一條讓普通人更容易明白的小路而已砖织,實際上款侵,各種開發(fā)權(quán)限讓瀏覽器很搞怪,有時候讓你覺得侧纯,跟所學(xué)的知識相悖新锈,根本沒有什么大一統(tǒng)的結(jié)論啊,比如眶熬,說js文件一加載就立刻執(zhí)行妹笆,然后出來了一個異步加載;谷歌瀏覽器是白屏的效果聋涨,可為啥火狐的是閃爍了晾浴?反正,明白一句話牍白,實踐出真知脊凰,越認(rèn)識到錯誤,越接近真實茂腥,好比小學(xué)里0是最小的狸涌,那是對的,到初中你再說就錯了最岗。
css文檔流的分析
首先css文件帕胆,這個研究對象,起初啊般渡,第一次跟著老師走的時候懒豹,是蒙的芙盘,沒有思路,只是跟著他走脸秽,模仿他的思路儒老,分析方法,現(xiàn)象驗證记餐,總結(jié)驮樊,這一套路吧,那時候憋屈啊片酝,自己討厭自己沒思路囚衔,聽得云里霧里的,只是記錄了一些所謂的結(jié)論和感官雕沿,以及對研究對象的一種很深很厭惡的感官了练湿。第二遍看視頻,對照著代碼晦炊,才能有自己的思路鞠鲜,而且有點成就感的是,對老師最后的幾個現(xiàn)象反而得不出大一統(tǒng)的結(jié)論想到了一些東西断国,心里還是比較滿足的。
我按我的猜想走吧榆苞。
這個研究對象啊稳衬,在html中css的位置有兩個,一個在head中坐漏,一個在body里薄疚。在這里,我先對css的添加樣式做個說明赊琳,不管是外部鏈接還是內(nèi)部的街夭,還是幾乎廢棄的在html標(biāo)簽里寫的,首先直接說最優(yōu)的就是內(nèi)部的躏筏,不用在發(fā)請求像外部的要文件了板丽,加載快,省事趁尼。拋去這個因素埃碱,再從位置入手。
先說一下酥泞,大一統(tǒng)的結(jié)論砚殿,從老師的代碼實驗中得到了,一個HTML文件芝囤,幾乎所有的css文件都是同時開始加載的似炎,不論位置辛萍。當(dāng)然,除去幾乎要費了的那種在html標(biāo)簽里寫的css,不是說它不適合或適合羡藐,只是說它沒法證明贩毕。
在head里的css,最明了传睹,簡單耳幢。這里的css文件是全部加載完成后才開始執(zhí)行,而且伴隨著執(zhí)行欧啤,html的內(nèi)容開始出現(xiàn)睛藻,符合渲染樹的步驟。
其實邢隧,我比較喜歡放這里店印,覺得很區(qū)塊化,而且倒慧,確實效果上很好的按摘。
在body里的css文件,加載時遵循順序纫谅,而無論上下方是何種html標(biāo)簽炫贤,都會在它們之后執(zhí)行,谷歌嘛付秕。但是關(guān)于圖片的加載時機的影響兰珍,這是我看到代碼實驗的一種猜想,僅僅限于谷歌瀏覽器上询吴,尤其是當(dāng)css上面或者下面有圖片或其他加載數(shù)據(jù)大時掠河,影響會很明顯,圖片會顯得不受css文件影響一樣猛计,該加載就加載唠摹。這里有一個因素是js文檔在head部時產(chǎn)生的阻礙作用,圖片會在所有css文件執(zhí)行后加載奉瘤,而把阻礙的js移到body底部時勾拉,圖片就好像不受css文件影響一樣,該加載就加載毛好,也不等css文件了望艺。
反正,對于研究加載的話肌访,顯得很蒼白找默,特立獨行的是js文件,最具主動性吼驶,它只會影響HTML和css惩激,而自身不受它們影響店煞。css加載幾乎是同時加載的,它影響html的一些元素如圖片的加載時機的风钻。執(zhí)行的話顷蟀,就比較簡單了,js文件加載后立即執(zhí)行骡技,css文件一個一個地執(zhí)行鸣个,這里非要針對影響的話,我又查了下資料布朦,貌似跟請求有關(guān)——
css文件的下載和渲染是同步的嗎? 還是先下載完, 再渲染?
不確定下載過程中是否同步做詞法分析parseCss囤萤,但是可能性很大,畢竟是種無損失的優(yōu)化方案是趴,但是最終肯定需要下載完再layout生成渲染樹涛舍,進(jìn)而渲染。
css文件的下載&執(zhí)行 和 html文件的下載&執(zhí)行同步嗎?
并行的唆途。但是需要注意一些限制富雅,比如一個域名下最大并發(fā)6個請求,再多就得串行肛搬。
圖形的加載 和 html文件的下載/執(zhí)行同步嗎, 音視頻呢, 別的資源呢?
同上没佑。
有沒有可能出現(xiàn)html文件/圖片/css文件/js文件同時下載的情況?
常態(tài)。
有沒有可能出現(xiàn)html/css文件/js文件同時執(zhí)行的情況?
html parse和css parse是并行的温赔,兩者完成后才會layout图筹、paint,新的css掛載會延遲layout让腹、paint。js parse會阻塞html parse 扣溺,所以后面的layout骇窍、paint一定不會同時執(zhí)行。
作者:錢多多
鏈接:https://www.zhihu.com/question/59024365/answer/161615976
來源:知乎
然后锥余,再說說無樣式加載腹纳,白屏,閃爍現(xiàn)象——這是瀏覽器加載與顯示頁面方式不同造成的驱犹。
谷歌呢是當(dāng)發(fā)現(xiàn)<link rel ="stylesheet"> 后立即停止渲染嘲恍,在所有css加載完成之前頁面上不會有任何內(nèi)容,所有白屏了雄驹〉枧#火狐呢有意思了,:<head>標(biāo)簽中的<link rel ="stylesheet">與Chrome和Safari中完全一致医舆,這些link標(biāo)簽全部加載完之前俘侠,頁面上不顯示任何內(nèi)容象缀,而<body>中的內(nèi)容則不阻塞任何內(nèi)容顯示,也就是說爷速,放<body>內(nèi)央星,先渲染沒有樣式的,再渲染有樣式的惫东。
repaint和reflow
- 簡介
repaint主要是針對某一個DOM元素進(jìn)行的重繪莉给,reflow則是回流,針對整個頁面的重排廉沮。字面意思來說:repaint就是重繪颓遏,reflow就是回流。repaint和reflow的目的是:展示一個新的頁面樣貌废封。 - 觸發(fā)
reflow是只要涉及到頁面排版和布局變動的州泊,元素本身布局變動,style變化漂洋,就會觸發(fā)遥皂,而且功耗很大。repaint是除了上述情況之外刽漂,還有就是標(biāo)簽本身的屬性渲染發(fā)生變化演训,顯示效果不一樣時,也會觸發(fā)贝咙,比如顏色變化样悟,不過功耗小得多。 - 避免功耗問題
能不改就不改庭猩,盡量避免reflow窟她,這就是想法了。
比如說經(jīng)常有些刷新的對象啊標(biāo)簽啊蔼水,比如動畫效果震糖,對象一變化,整個頁面就相當(dāng)于刷新了趴腋,所以吊说,變動影響最小的就是把對象搞成絕對定位,或其他优炬,反正脫離文檔流就行颁井,并且如動畫一類的可控變化,讓變化頻率變小蠢护。
多用class選擇器雅宾,減少計算的量,精簡css的邏輯量糊余,然后從這個角度入手秀又,就是想辦法把css樹結(jié)構(gòu)變得小巧单寂,所以DOM元素能不用css的就不用,所以減少外部鏈接引入css文件吐辙。
說了這么多宣决,都是跟css有關(guān)的,心里有點意思的昏苏,莫名其妙哦尊沸,這可是在學(xué)js啊贤惯!只能說明洼专,學(xué)css時,自己太蠢孵构,僅僅當(dāng)成了靜態(tài)頁面屁商,給它們化妝打扮了,自以為可以為所欲為颈墅,可是站在更廣闊的大局觀蜡镶,看到的風(fēng)景卻是很不一樣的。這里的css里的東西恤筛,我其實偷懶了官还,時間關(guān)系,根本沒有自己把實例一一展示毒坛,我僅僅是通過視頻里的代碼展示推出了一些猜想望伦,并自覺地認(rèn)為,這僅僅是一個谷歌瀏覽器啊煎殷,那IE屯伞,火狐等等其他的呢?難道都要一一驗證豪直?我暫時沒有時間了愕掏,只能說這個是未完結(jié)版,待續(xù)顶伞,,剑梳,
js文件的分析
終于到了新鮮貨了哦唆貌。不過js文件其實算是比較有原則的吧,畢竟它是為了實現(xiàn)功能和效果的垢乙,相比前兩者來說锨咙,卻是有些特立獨行。相比于如今的寬帶追逮,研究白屏或者內(nèi)容閃爍酪刀,比較無聊在于粹舵,幾乎沒有這種顯示體驗了,研究的意義在于骂倘,哦眼滤,讓我明白瀏覽器的渲染邏輯的更清晰化更具有邏輯,出來了一種現(xiàn)象历涝,哦诅需,我可以解釋,我懂得荧库!所有我覺得我是前端工程師堰塌!包括js文件在整個運行過程中的位置,我還是有必要說說滴分衫。
js文件的研究场刑,就不那么俗套了,直接說位置放在head和body中 的情況吧蚪战。
先說牵现,一般情況下,大一統(tǒng)的結(jié)論就是屎勘,加載了js文件施籍,立刻執(zhí)行,所以會阻礙后面的文件的執(zhí)行概漱,也會阻礙后面的內(nèi)容的展示的丑慎。所以,一般情況下瓤摧,都會把這個家伙放到body的最后竿裂,反正它就是個功能效果,對頁面的顯示體驗影響不大照弥,那就先讓頁面顯示出來腻异,最后再加載頁面的功能效果。并且js文件有作用元素这揣,如果元素還沒出來悔常,js先執(zhí)行了,就會報錯给赞。
如果放head里机打,不用說了,按標(biāo)簽順序來片迅,到了它這里残邀,開始加載,加載的話不會影響其他哥們的加載,但是加載 完了芥挣,就立刻執(zhí)行驱闷,執(zhí)行時,它下面的css不能執(zhí)行空免,html內(nèi)容不能展示的空另。
在body里的js文件嗯,一般來說鼓蜒,應(yīng)該也是跟head里的差不多的痹换,但是偏偏有特例,嗯都弹,在谷歌里娇豫,body里的js文件,有一個很有意思的現(xiàn)象畅厢,所以不是結(jié)論冯痢,視頻里老師稱之為谷歌的自己的優(yōu)化——body里的js文件的first child,嗯就是大兒子的意思框杜,有特殊待遇浦楣,在比其他的js兄弟們更早地加載執(zhí)行,如何更早咪辱?幾乎相當(dāng)于html解析到它這里時振劳,做了個停頓,判斷處理油狂,一秒左右历恐,就開始加載了,這不算特殊专筷。從除了它之外弱贼,其他的兄弟們受到隊伍前面的css文件執(zhí)行的阻礙,前面的執(zhí)行完了磷蛹,它們才開始加載吮旅,所以大兒子是個異類。
然后味咳,說到底庇勃,研究js如果太鉆牛角尖到具體的加載時機上,其實太復(fù)雜了槽驶,這僅僅是一個谷歌匪凉,還是那句話,不是瀏覽器開發(fā)者捺檬,就不懂得制定規(guī)則,只能按規(guī)則來贸铜,但是一個開發(fā)者一個規(guī)則堡纬,亂七八糟的聂受,對初學(xué)者甚至于僅僅是個前端層次的大局來說,很無力烤镐,尤其是現(xiàn)在網(wǎng)速如此發(fā)達(dá)了蛋济,我們應(yīng)該更關(guān)注于一些最基本的運行原理,比如js的阻礙效果炮叶,如何優(yōu)化碗旅?做到看到現(xiàn)象,能夠模擬镜悉,解析出來邏輯祟辟,就可以了,哪里有那么多大一統(tǒng)的總結(jié)侣肄?
異步加載
defer 和 async
避免js文件的加載和執(zhí)行擋路旧困,于是有兩個屬性。
defer 和 async 在網(wǎng)絡(luò)讀燃诠(下載)這塊兒是一樣的吼具,都是異步的(相較于 HTML 解析)。
它倆的差別在于腳本下載完之后何時執(zhí)行矩距,顯然 defer 是最接近我們對于應(yīng)用腳本加載和執(zhí)行的要求的拗盒。
關(guān)于 defer,它是按照加載順序執(zhí)行腳本的锥债,這一點要善加利用陡蝇。
async 則是一個亂序執(zhí)行的主,反正對它來說腳本的加載和執(zhí)行是緊緊挨著的赞弥,所以不管你聲明的順序如何毅整,只要它加載完了就會立刻執(zhí)行。
仔細(xì)想想绽左,async 對于應(yīng)用腳本的用處不大悼嫉,因為它完全不考慮依賴(哪怕是最低級的順序執(zhí)行),不過它對于那些可以不依賴任何腳本或不被任何腳本依賴的腳本來說卻是非常合適的拼窥,最典型的例子:網(wǎng)頁的廣告戏蔑。
此處拿來主義《defer和async的區(qū)別》。