摘要:前言見(jiàn)解有限,如有描述不當(dāng)之處,請(qǐng)幫忙指出,如有錯(cuò)誤,會(huì)及時(shí)修正。為什么要梳理這篇文章最近恰好被問(wèn)到這方面的問(wèn)題,嘗試整理后發(fā)現(xiàn),這道題的覆蓋面可以非常廣,很適合作為一道承載知識(shí)體系的題目。
前言
見(jiàn)解有限,如有描述不當(dāng)之處,請(qǐng)幫忙指出,如有錯(cuò)誤,會(huì)及時(shí)修正。
為什么要梳理這篇文章?
最近恰好被問(wèn)到這方面的問(wèn)題,嘗試整理后發(fā)現(xiàn),這道題的覆蓋面可以非常廣,很適合作為一道承載知識(shí)體系的題目。
關(guān)于這道題目的吐槽暫且不提(這是一道被提到無(wú)數(shù)次的題,得到不少人的贊同,也被很多人反感),本文的目的是如何借助這道題梳理自己的前端知識(shí)體系!
竊認(rèn)為,每一個(gè)前端人員,如果要往更高階發(fā)展,必然會(huì)將自己的知識(shí)體系梳理一遍,沒(méi)有牢固的知識(shí)體系,無(wú)法往更高處走!
展現(xiàn)形式:本文并不是將所有的知識(shí)點(diǎn)列一遍,而是偏向于分析+梳理
內(nèi)容:在本文中只會(huì)梳理一些比較重要的前端向知識(shí)點(diǎn),其它的可能會(huì)被省略
目標(biāo):本文的目標(biāo)是梳理一個(gè)較為完整的前端向知識(shí)體系
本文是個(gè)人階段性梳理知識(shí)體系的成果,然后加以修繕后發(fā)布成文章,因此并不確保適用于所有人員,但是,個(gè)人認(rèn)為本文還是有一定參考價(jià)值的
另外,如有不同見(jiàn)解,可以一起討論
----------超長(zhǎng)文預(yù)警,需要花費(fèi)大量時(shí)間。----------
本文適合有一定經(jīng)驗(yàn)的前端人員,新手請(qǐng)規(guī)避。
本文內(nèi)容超多,建議先了解主干,然后分成多批次閱讀。
本文是前端向,以前端領(lǐng)域的知識(shí)為重點(diǎn)
大綱對(duì)知識(shí)體系進(jìn)行一次預(yù)評(píng)級(jí)
為什么說(shuō)知識(shí)體系如此重要?
梳理主干流程
從瀏覽器接收url到開(kāi)啟網(wǎng)絡(luò)請(qǐng)求線程
多進(jìn)程的瀏覽器
多線程的瀏覽器內(nèi)核
解析URL
網(wǎng)絡(luò)請(qǐng)求都是多帶帶的線程
更多
開(kāi)啟網(wǎng)絡(luò)線程到發(fā)出一個(gè)完整的http請(qǐng)求
DNS查詢得到IP
tcp/ip請(qǐng)求
五層因特網(wǎng)協(xié)議棧
從服務(wù)器接收到請(qǐng)求到對(duì)應(yīng)后臺(tái)接收到請(qǐng)求
負(fù)載均衡
后臺(tái)的處理
后臺(tái)和前臺(tái)的http交互
http報(bào)文結(jié)構(gòu)
cookie以及優(yōu)化
gzip壓縮
長(zhǎng)連接與短連接
http 2.0
https
多帶帶拎出來(lái)的緩存問(wèn)題,http的緩存
強(qiáng)緩存與弱緩存
緩存頭部簡(jiǎn)述
頭部的區(qū)別
解析頁(yè)面流程
流程簡(jiǎn)述
HTML解析,構(gòu)建DOM
生成CSS規(guī)則
構(gòu)建渲染樹(shù)
渲染
簡(jiǎn)單層與復(fù)合層
Chrome中的調(diào)試
資源外鏈的下載
loaded和domcontentloaded
CSS的可視化格式模型
包含塊(Containing Block)
控制框(Controlling Box)
BFC(Block Formatting Context)
IFC(Inline Formatting Context)
其它
JS引擎解析過(guò)程
JS的解釋階段
JS的預(yù)處理階段
JS的執(zhí)行階段
回收機(jī)制
其它
總結(jié)
對(duì)知識(shí)體系進(jìn)行一次預(yù)評(píng)級(jí)看到這道題目,不借助搜索引擎,自己的心里是否有一個(gè)答案?
這里,以目前的經(jīng)驗(yàn)(了解過(guò)一些處于不同階段的相關(guān)前端人員的情況),大概有以下幾種情況:(以下都是以點(diǎn)見(jiàn)面,實(shí)際上不同階段人員一般都會(huì)有其它的隱藏知識(shí)點(diǎn)的)
level1:完全沒(méi)什么概念的,支支吾吾的回答,一般就是這種水平(大致形象點(diǎn)描述):
瀏覽器發(fā)起請(qǐng)求,服務(wù)端返回?cái)?shù)據(jù),然后前端解析成網(wǎng)頁(yè),執(zhí)行腳本。。。
這類人員一般都是:
萌新(剛接觸前端的,包括0-6個(gè)月都有可能有這種回答)
沉淀人員(就是那種可能已經(jīng)接觸了前端幾年,但是仍然處于初級(jí)階段的那種。。。)
當(dāng)然了,后者一般還會(huì)偶爾提下http、后臺(tái)、瀏覽器渲染,js引擎等等關(guān)鍵字,但基本都是一詳細(xì)的問(wèn)就不知道了。。。
level2:已經(jīng)有初步概念,但是可能沒(méi)有完整梳理過(guò),導(dǎo)致無(wú)法形成一個(gè)完整的體系,或者是很多細(xì)節(jié)都不會(huì)展開(kāi),大概是這樣子的:(可能符合若干條)
知道瀏覽器輸入url后會(huì)有http請(qǐng)求這個(gè)概念
有后臺(tái)這個(gè)概念,大致知道前后端的交互,知道前后端只要靠http報(bào)文通信
知道瀏覽器接收到數(shù)據(jù)后會(huì)進(jìn)行解析,有一定概念,但是具體流程不熟悉(如render樹(shù)構(gòu)建流程,layout、paint,復(fù)合層與簡(jiǎn)單層,常用優(yōu)化方案等不是很熟悉)
對(duì)于js引擎的解析流程有一定概念,但是細(xì)節(jié)不熟悉(如具體的形參,函數(shù),變量提升,執(zhí)行上下文以及VO、AO、作用域鏈,回收機(jī)制等概念不是很熟悉)
如可能知道一些http規(guī)范初步概念,但是不熟悉(如http報(bào)文結(jié)構(gòu),常用頭部,緩存機(jī)制,http2.0,https等特性,跨域與web安全等不是很熟悉)
到這里,看到這上面一大堆的概念后,心里應(yīng)該也會(huì)有點(diǎn)底了。。。
實(shí)際上,大部分的前端人員可能都處于level2,但是,跳出這個(gè)階段并不容易,一般需要積累,不斷學(xué)習(xí),才能水到渠成
這類人員一般都是:
工作1-3年左右的普通人員(占大多數(shù),而且大多數(shù)人員工作3年左右并沒(méi)有實(shí)質(zhì)上的提升)
工作3年以上的老人(這部分人大多都業(yè)務(wù)十分嫻熟,一個(gè)當(dāng)好幾個(gè)用,但是,基礎(chǔ)比較薄弱,可能沒(méi)有嘗試寫(xiě)過(guò)框架、組件、腳手架等)
大部分的初中級(jí)都陷在這個(gè)階段,如果要突破,不斷學(xué)習(xí),積累,自然能水到渠成,打通任督二脈
level3:基本能到這一步的,不是高階就是接近高階,因?yàn)楹芏喔拍畈⒉皇强勘尘湍芾斫獾模斫膺@么多,需形成體系,一般都需要積累,非一日之功。
一般包括什么樣的回答呢?(這里就以自己的簡(jiǎn)略回答進(jìn)行舉例),一般這個(gè)階段的人員都會(huì)符合若干條(不一定全部,當(dāng)然可能還有些是這里遺漏的):
首先略去那些鍵盤(pán)輸入、和操作系統(tǒng)交互、以及屏幕顯示原理、網(wǎng)卡等硬件交互之類的(前端向中,很多硬件原理暫時(shí)略去。。。)
對(duì)瀏覽器模型有整體概念,知道瀏覽器是多進(jìn)程的,瀏覽器內(nèi)核是多線程的,清楚進(jìn)程與線程之間得區(qū)別,以及輸入url后會(huì)開(kāi)一個(gè)新的網(wǎng)絡(luò)線程
對(duì)從開(kāi)啟網(wǎng)絡(luò)線程到發(fā)出一個(gè)完整的http請(qǐng)求中間的過(guò)程有所了解(如dns查詢,tcp/ip鏈接,五層因特網(wǎng)協(xié)議棧等等,以及一些優(yōu)化方案,如dns-prefetch)
對(duì)從服務(wù)器接收到請(qǐng)求到對(duì)應(yīng)后臺(tái)接收到請(qǐng)求有一定了解(如負(fù)載均衡,安全攔截以及后臺(tái)代碼處理等)
對(duì)后臺(tái)和前臺(tái)的http交互熟悉(包括http報(bào)文結(jié)構(gòu),場(chǎng)景頭部,cookie,跨域,web安全,http緩存,http2.0,https等)
對(duì)瀏覽器接收到http數(shù)據(jù)包后的解析流程熟悉(包括解析html,詞法分析然后解析成dom樹(shù)、解析css生成css規(guī)則樹(shù)、合并成render樹(shù),然后layout、painting渲染、里面可能還包括復(fù)合圖層的合成、GPU繪制、外鏈處理、加載順序等)
對(duì)JS引擎解析過(guò)程熟悉(包括JS的解釋,預(yù)處理,執(zhí)行上下文,VO,作用域鏈,this,回收機(jī)制等)
可以看到,上述包括了一大堆的概念,僅僅是偏前端向,而且沒(méi)有詳細(xì)展開(kāi),就已經(jīng)如此之多的概念了,所以,個(gè)人認(rèn)為如果沒(méi)有自己的見(jiàn)解,沒(méi)有形成自己的知識(shí)體系,僅僅是看看,背背是沒(méi)用的,過(guò)一段時(shí)間就會(huì)忘光了。
再說(shuō)下一般這個(gè)階段的都可能是什么樣的人吧。(不一定準(zhǔn)確,這里主要是靠少部分現(xiàn)實(shí)以及大部分推測(cè)得出)
工作2年以上的前端(基本上如果按正常進(jìn)度的話,至少接觸前端兩年左右才會(huì)開(kāi)始走向高階,當(dāng)然,現(xiàn)在很多都是上學(xué)時(shí)就開(kāi)始學(xué)了的,還有部分是天賦異稟,不好預(yù)估。。。)
或者是已經(jīng)十分熟悉其它某門(mén)語(yǔ)言,再轉(zhuǎn)前端的人(基本上是很快就可以將前端水準(zhǔn)提升上去)
一般符合這個(gè)條件的都會(huì)有各種隱藏屬性(如看過(guò)各大框架、組件的源碼,寫(xiě)過(guò)自己的組件、框架、腳手架,做過(guò)大型項(xiàng)目,整理過(guò)若干精品博文等)
level4:由于本人層次尚未達(dá)到,所以大致說(shuō)下自己的見(jiàn)解吧。
一般這個(gè)層次,很多大佬都并不僅僅是某個(gè)技術(shù)棧了,而是成為了技術(shù)專家,技術(shù)leader之類的角色。所以僅僅是回答某個(gè)技術(shù)問(wèn)題已經(jīng)無(wú)法看出水準(zhǔn)了,
可能更多的要看架構(gòu),整體把控,大型工程構(gòu)建能力等等
不過(guò),對(duì)于某些執(zhí)著于技術(shù)的大佬,大概會(huì)有一些回答吧:(猜的)
從鍵盤(pán)談起到系統(tǒng)交互,從瀏覽器到CPU,從調(diào)度機(jī)制到系統(tǒng)內(nèi)核,從數(shù)據(jù)請(qǐng)求到二進(jìn)制、匯編,從GPU繪圖到LCD顯示,然后再分析系統(tǒng)底層的進(jìn)程、內(nèi)存等等
總之,從軟件到硬件,到材料,到分子,原子,量子,薛定諤的貓,人類起源,宇宙大爆炸,平行宇宙?感覺(jué)都毫無(wú)違和感。。。
這點(diǎn)可以參考下本題的原始出處:
http://fex.baidu.com/blog/2014/05/what-happen/
為什么說(shuō)知識(shí)體系如此重要?為什么說(shuō)知識(shí)體系如此重要呢?這里舉幾個(gè)例子
假設(shè)有被問(wèn)到這樣一道題目(隨意想到的一個(gè)):
如何理解getComputedStyle
在尚未梳理知識(shí)體系前,大概會(huì)這樣回答:
普通版本:getComputedStyle會(huì)獲取當(dāng)前元素所有最終使用的CSS屬性值(最終計(jì)算后的結(jié)果),通過(guò)window.getComputedStyle等價(jià)于document.defaultView.getComputedStyle調(diào)用
詳細(xì)版本:window.getComputedStyle(elem, null).getPropertyValue("height")可能的值為100px,而且,就算是css上寫(xiě)的是inherit,getComputedStyle也會(huì)把它最終計(jì)算出來(lái)的。不過(guò)注意,如果元素的背景色透明,那么getComputedStyle獲取出來(lái)的就是透明的這個(gè)背景(因?yàn)橥该鞅旧硪彩怯行У模粫?huì)是父節(jié)點(diǎn)的背景。所以它不一定是最終顯示的顏色。
就這個(gè)API來(lái)說(shuō),上述的回答已經(jīng)比較全面了。
但是,其實(shí)它是可以繼續(xù)延伸的。
譬如現(xiàn)在會(huì)這樣回答:
getComputedStyle會(huì)獲取當(dāng)前元素所有最終使用的CSS屬性值,window.和document.defaultView.等價(jià)...
getComputedStyle會(huì)引起回流,因?yàn)樗枰@取祖先節(jié)點(diǎn)的一些信息進(jìn)行計(jì)算(譬如寬高等),所以用的時(shí)候慎用,回流會(huì)引起性能問(wèn)題。然后合適的話會(huì)將話題引導(dǎo)回流,重繪,瀏覽器渲染原理等等。當(dāng)然也可以列舉一些其它會(huì)引發(fā)回流的操作,如offsetXXX,scrollXXX,clientXXX,currentStyle等等
再舉一個(gè)例子:
visibility: hidden和display: none的區(qū)別
可以如下回答:
普通回答,一個(gè)隱藏,但占據(jù)位置,一個(gè)隱藏,不占據(jù)位置
進(jìn)一步,display由于隱藏后不占據(jù)位置,所以造成了dom樹(shù)的改變,會(huì)引發(fā)回流,代價(jià)較大
再進(jìn)一步,當(dāng)一個(gè)頁(yè)面某個(gè)元素經(jīng)常需要切換display時(shí)如何優(yōu)化,一般會(huì)用復(fù)合層優(yōu)化,或者要求低一點(diǎn)用absolute讓其脫離普通文檔流也行。然后可以將話題引到普通文檔流,absolute文檔流,復(fù)合圖層的區(qū)別,
再進(jìn)一步可以描述下瀏覽器渲染原理以及復(fù)合圖層和普通圖層的繪制區(qū)別(復(fù)合圖層多帶帶分配資源,獨(dú)立繪制,性能提升,但是不能過(guò)多,還有隱式合成等等)
上面這些大概就是知識(shí)系統(tǒng)化后的回答,會(huì)更全面,容易由淺入深,而且一有機(jī)會(huì)就可以往更底層挖
前端向知識(shí)的重點(diǎn)此部分的內(nèi)容是站在個(gè)人視角分析的,并不是說(shuō)就一定是正確答案
首先明確,計(jì)算機(jī)方面的知識(shí)是可以無(wú)窮無(wú)盡的挖的,而本文的重點(diǎn)是梳理前端向的重點(diǎn)知識(shí)
對(duì)于前端向(這里可能沒(méi)有提到node.js之類的,更多的是指客戶端前端),這里將知識(shí)點(diǎn)按重要程度劃分成以下幾大類:
核心知識(shí),必須掌握的,也是最基礎(chǔ)的,譬如瀏覽器模型,渲染原理,JS解析過(guò)程,JS運(yùn)行機(jī)制等,作為骨架來(lái)承載知識(shí)體系
重點(diǎn)知識(shí),往往每一塊都是一個(gè)知識(shí)點(diǎn),而且這些知識(shí)點(diǎn)都很重要,譬如http相關(guān),web安全相關(guān),跨域處理等
拓展知識(shí),這一塊可能更多的是了解,稍微實(shí)踐過(guò),但是認(rèn)識(shí)上可能沒(méi)有上面那么深刻,譬如五層因特網(wǎng)協(xié)議棧,hybrid模式,移動(dòng)原生開(kāi)發(fā),后臺(tái)相關(guān)等等(當(dāng)然,在不同領(lǐng)域,可能有某些知識(shí)就上升到重點(diǎn)知識(shí)層次了,譬如hybrid開(kāi)發(fā)時(shí),懂原生開(kāi)發(fā)是很重要的)
為什么要按上面這種方式劃分?
這大概與個(gè)人的技術(shù)成長(zhǎng)有關(guān)。
記得最開(kāi)始學(xué)前端知識(shí)時(shí),是一點(diǎn)一點(diǎn)的積累,一個(gè)知識(shí)點(diǎn)一個(gè)知識(shí)點(diǎn)的攻克。
就這樣,雖然在很長(zhǎng)一段時(shí)間內(nèi)積累了不少的知識(shí),但是,總是無(wú)法將它串聯(lián)到一起。每次梳理時(shí)都是很分散的,無(wú)法保持思路連貫性。
直到后來(lái),在將瀏覽器渲染原理、JS運(yùn)行機(jī)制、JS引擎解析流程梳理一遍后,感覺(jué)就跟打通了任督二脈一樣,有了一個(gè)整體的架構(gòu),以前的知識(shí)點(diǎn)都連貫起來(lái)了。
梳理出了一個(gè)知識(shí)體系,以后就算再學(xué)新的知識(shí),也會(huì)盡量往這個(gè)體系上靠攏,環(huán)環(huán)相扣,更容易理解,也更不容易遺忘
梳理主干流程回到這道題上,如何回答呢?先梳理一個(gè)骨架
知識(shí)體系中,最重要的是骨架,脈絡(luò)。有了骨架后,才方便填充細(xì)節(jié)。所以,先梳理下主干流程:
1. 從瀏覽器接收url到開(kāi)啟網(wǎng)絡(luò)請(qǐng)求線程(這一部分可以展開(kāi)瀏覽器的機(jī)制以及進(jìn)程與線程之間的關(guān)系) 2. 開(kāi)啟網(wǎng)絡(luò)線程到發(fā)出一個(gè)完整的http請(qǐng)求(這一部分涉及到dns查詢,tcp/ip請(qǐng)求,五層因特網(wǎng)協(xié)議棧等知識(shí)) 3. 從服務(wù)器接收到請(qǐng)求到對(duì)應(yīng)后臺(tái)接收到請(qǐng)求(這一部分可能涉及到負(fù)載均衡,安全攔截以及后臺(tái)內(nèi)部的處理等等) 4. 后臺(tái)和前臺(tái)的http交互(這一部分包括http頭部、響應(yīng)碼、報(bào)文結(jié)構(gòu)、cookie等知識(shí),可以提下靜態(tài)資源的cookie優(yōu)化,以及編碼解碼,如gzip壓縮等) 5. 多帶帶拎出來(lái)的緩存問(wèn)題,http的緩存(這部分包括http緩存頭部,etag,catch-control等) 6. 瀏覽器接收到http數(shù)據(jù)包后的解析流程(解析html-詞法分析然后解析成dom樹(shù)、解析css生成css規(guī)則樹(shù)、合并成render樹(shù),然后layout、painting渲染、復(fù)合圖層的合成、GPU繪制、外鏈資源的處理、loaded和domcontentloaded等) 7. CSS的可視化格式模型(元素的渲染規(guī)則,如包含塊,控制框,BFC,IFC等概念) 8. JS引擎解析過(guò)程(JS的解釋階段,預(yù)處理階段,執(zhí)行階段生成執(zhí)行上下文,VO,作用域鏈、回收機(jī)制等等) 9. 其它(可以拓展不同的知識(shí)模塊,如跨域,web安全,hybrid模式等等內(nèi)容)
梳理出主干骨架,然后就需要往骨架上填充細(xì)節(jié)內(nèi)容
從瀏覽器接收url到開(kāi)啟網(wǎng)絡(luò)請(qǐng)求線程這一部分展開(kāi)的內(nèi)容是:瀏覽器進(jìn)程/線程模型,JS的運(yùn)行機(jī)制
多進(jìn)程的瀏覽器瀏覽器是多進(jìn)程的,有一個(gè)主控進(jìn)程,以及每一個(gè)tab頁(yè)面都會(huì)新開(kāi)一個(gè)進(jìn)程(某些情況下多個(gè)tab會(huì)合并進(jìn)程)
進(jìn)程可能包括主控進(jìn)程,插件進(jìn)程,GPU,tab頁(yè)(瀏覽器內(nèi)核)等等
Browser進(jìn)程:瀏覽器的主進(jìn)程(負(fù)責(zé)協(xié)調(diào)、主控),只有一個(gè)
第三方插件進(jìn)程:每種類型的插件對(duì)應(yīng)一個(gè)進(jìn)程,僅當(dāng)使用該插件時(shí)才創(chuàng)建
GPU進(jìn)程:最多一個(gè),用于3D繪制
瀏覽器渲染進(jìn)程(內(nèi)核):默認(rèn)每個(gè)Tab頁(yè)面一個(gè)進(jìn)程,互不影響,控制頁(yè)面渲染,腳本執(zhí)行,事件處理等(有時(shí)候會(huì)優(yōu)化,如多個(gè)空白tab會(huì)合并成一個(gè)進(jìn)程)
如下圖:
多線程的瀏覽器內(nèi)核每一個(gè)tab頁(yè)面可以看作是瀏覽器內(nèi)核進(jìn)程,然后這個(gè)進(jìn)程是多線程的,它有幾大類子線程
GUI線程
JS引擎線程
事件觸發(fā)線程
定時(shí)器線程
網(wǎng)絡(luò)請(qǐng)求線程
可以看到,里面的JS引擎是內(nèi)核進(jìn)程中的一個(gè)線程,這也是為什么常說(shuō)JS引擎是單線程的
解析URL輸入U(xiǎn)RL后,會(huì)進(jìn)行解析(URL的本質(zhì)就是統(tǒng)一資源定位符)
URL一般包括幾大部分:
protocol,協(xié)議頭,譬如有http,ftp等
host,主機(jī)域名或IP地址
port,端口號(hào)
path,目錄路徑
query,即查詢參數(shù)
fragment,即#后的hash值,一般用來(lái)定位到某個(gè)位置
網(wǎng)絡(luò)請(qǐng)求都是多帶帶的線程每次網(wǎng)絡(luò)請(qǐng)求時(shí)都需要開(kāi)辟多帶帶的線程進(jìn)行,譬如如果URL解析到http協(xié)議,就會(huì)新建一個(gè)網(wǎng)絡(luò)線程去處理資源下載
因此瀏覽器會(huì)根據(jù)解析出得協(xié)議,開(kāi)辟一個(gè)網(wǎng)絡(luò)線程,前往請(qǐng)求資源(這里,暫時(shí)理解為是瀏覽器內(nèi)核開(kāi)辟的,如有錯(cuò)誤,后續(xù)修復(fù))
更多由于篇幅關(guān)系,這里就大概介紹一個(gè)主干流程,關(guān)于瀏覽器的進(jìn)程機(jī)制,更多可以參考以前總結(jié)的一篇文章(因?yàn)閮?nèi)容實(shí)在過(guò)多,里面包括JS運(yùn)行機(jī)制,進(jìn)程線程的詳解)
從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制最全面的一次梳理
開(kāi)啟網(wǎng)絡(luò)線程到發(fā)出一個(gè)完整的http請(qǐng)求這一部分主要內(nèi)容包括:dns查詢,tcp/ip請(qǐng)求構(gòu)建,五層因特網(wǎng)協(xié)議棧等等
仍然是先梳理主干,有些詳細(xì)的過(guò)程不展開(kāi)(因?yàn)檎归_(kāi)的話內(nèi)容過(guò)多)
DNS查詢得到IP如果輸入的是域名,需要進(jìn)行dns解析成IP,大致流程:
如果瀏覽器有緩存,直接使用瀏覽器緩存,否則使用本機(jī)緩存,再?zèng)]有的話就是用host
如果本地沒(méi)有,就向dns域名服務(wù)器查詢(當(dāng)然,中間可能還會(huì)經(jīng)過(guò)路由,也有緩存等),查詢到對(duì)應(yīng)的IP
注意,域名查詢時(shí)有可能是經(jīng)過(guò)了CDN調(diào)度器的(如果有cdn存儲(chǔ)功能的話)
而且,需要知道dns解析是很耗時(shí)的,因此如果解析域名過(guò)多,會(huì)讓首屏加載變得過(guò)慢,可以考慮dns-prefetch優(yōu)化
這一塊可以深入展開(kāi),具體請(qǐng)去網(wǎng)上搜索,這里就不占篇幅了(網(wǎng)上可以看到很詳細(xì)的解答)
tcp/ip請(qǐng)求http的本質(zhì)就是tcp/ip請(qǐng)求
需要了解3次握手規(guī)則建立連接以及斷開(kāi)連接時(shí)的四次揮手
tcp將http長(zhǎng)報(bào)文劃分為短報(bào)文,通過(guò)三次握手與服務(wù)端建立連接,進(jìn)行可靠傳輸
三次握手的步驟:(抽象派)
客戶端:hello,你是server么? 服務(wù)端:hello,我是server,你是client么 客戶端:yes,我是client
建立連接成功后,接下來(lái)就正式傳輸數(shù)據(jù)
然后,待到斷開(kāi)連接時(shí),需要進(jìn)行四次揮手(因?yàn)槭侨p工的,所以需要四次揮手)
四次揮手的步驟:(抽象派)
主動(dòng)方:我已經(jīng)關(guān)閉了向你那邊的主動(dòng)通道了,只能被動(dòng)接收了 被動(dòng)方:收到通道關(guān)閉的信息 被動(dòng)方:那我也告訴你,我這邊向你的主動(dòng)通道也關(guān)閉了 主動(dòng)方:最后收到數(shù)據(jù),之后雙方無(wú)法通信
tcp/ip的并發(fā)限制
瀏覽器對(duì)同一域名下并發(fā)的tcp連接是有限制的(2-10個(gè)不等)
而且在http1.0中往往一個(gè)資源下載就需要對(duì)應(yīng)一個(gè)tcp/ip請(qǐng)求
所以針對(duì)這個(gè)瓶頸,又出現(xiàn)了很多的資源優(yōu)化方案
get和post的區(qū)別
get和post雖然本質(zhì)都是tcp/ip,但兩者除了在http層面外,在tcp/ip層面也有區(qū)別。
get會(huì)產(chǎn)生一個(gè)tcp數(shù)據(jù)包,post兩個(gè)
具體就是:
get請(qǐng)求時(shí),瀏覽器會(huì)把headers和data一起發(fā)送出去,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù)),
post請(qǐng)求時(shí),瀏覽器先發(fā)送headers,服務(wù)器響應(yīng)100 continue,
瀏覽器再發(fā)送data,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù))。
再說(shuō)一點(diǎn),這里的區(qū)別是specification(規(guī)范)層面,而不是implementation(對(duì)規(guī)范的實(shí)現(xiàn))
五層因特網(wǎng)協(xié)議棧其實(shí)這個(gè)概念挺難記全的,記不全沒(méi)關(guān)系,但是要有一個(gè)整體概念
其實(shí)就是一個(gè)概念: 從客戶端發(fā)出http請(qǐng)求到服務(wù)器接收,中間會(huì)經(jīng)過(guò)一系列的流程。
簡(jiǎn)括就是:
從應(yīng)用層的發(fā)送http請(qǐng)求,到傳輸層通過(guò)三次握手建立tcp/ip連接,再到網(wǎng)絡(luò)層的ip尋址,再到數(shù)據(jù)鏈路層的封裝成幀,最后到物理層的利用物理介質(zhì)傳輸。
當(dāng)然,服務(wù)端的接收就是反過(guò)來(lái)的步驟
五層因特網(wǎng)協(xié)議棧其實(shí)就是:
1.應(yīng)用層(dns,http) DNS解析成IP并發(fā)送http請(qǐng)求 2.傳輸層(tcp,udp) 建立tcp連接(三次握手) 3.網(wǎng)絡(luò)層(IP,ARP) IP尋址 4.數(shù)據(jù)鏈路層(PPP) 封裝成幀 5.物理層(利用物理介質(zhì)傳輸比特流) 物理傳輸(然后傳輸?shù)臅r(shí)候通過(guò)雙絞線,電磁波等各種介質(zhì))
當(dāng)然,其實(shí)也有一個(gè)完整的OSI七層框架,與之相比,多了會(huì)話層、表示層。
OSI七層框架:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層、應(yīng)用層
表示層:主要處理兩個(gè)通信系統(tǒng)中交換信息的表示方式,包括數(shù)據(jù)格式交換,數(shù)據(jù)加密與解密,數(shù)據(jù)壓縮與終端類型轉(zhuǎn)換等 會(huì)話層:它具體管理不同用戶和進(jìn)程之間的對(duì)話,如控制登陸和注銷過(guò)程從服務(wù)器接收到請(qǐng)求到對(duì)應(yīng)后臺(tái)接收到請(qǐng)求
服務(wù)端在接收到請(qǐng)求時(shí),內(nèi)部會(huì)進(jìn)行很多的處理
這里由于不是專業(yè)的后端分析,所以只是簡(jiǎn)單的介紹下,不深入
負(fù)載均衡對(duì)于大型的項(xiàng)目,由于并發(fā)訪問(wèn)量很大,所以往往一臺(tái)服務(wù)器是吃不消的,所以一般會(huì)有若干臺(tái)服務(wù)器組成一個(gè)集群,然后配合反向代理實(shí)現(xiàn)負(fù)載均衡
當(dāng)然了,負(fù)載均衡不止這一種實(shí)現(xiàn)方式,這里不深入...
簡(jiǎn)單的說(shuō):
用戶發(fā)起的請(qǐng)求都指向調(diào)度服務(wù)器(反向代理服務(wù)器,譬如安裝了nginx控制負(fù)載均衡),然后調(diào)度服務(wù)器根據(jù)實(shí)際的調(diào)度算法,分配不同的請(qǐng)求給對(duì)應(yīng)集群中的服務(wù)器執(zhí)行,然后調(diào)度器等待實(shí)際服務(wù)器的HTTP響應(yīng),并將它反饋給用戶
后臺(tái)的處理一般后臺(tái)都是部署到容器中的,所以一般為:
先是容器接受到請(qǐng)求(如tomcat容器)
然后對(duì)應(yīng)容器中的后臺(tái)程序接收到請(qǐng)求(如java程序)
然后就是后臺(tái)會(huì)有自己的統(tǒng)一處理,處理完后響應(yīng)響應(yīng)結(jié)果
概括下:
一般有的后端是有統(tǒng)一的驗(yàn)證的,如安全攔截,跨域驗(yàn)證
如果這一步不符合規(guī)則,就直接返回了相應(yīng)的http報(bào)文(如拒絕請(qǐng)求等)
然后當(dāng)驗(yàn)證通過(guò)后,才會(huì)進(jìn)入實(shí)際的后臺(tái)代碼,此時(shí)是程序接收到請(qǐng)求,然后執(zhí)行(譬如查詢數(shù)據(jù)庫(kù),大量計(jì)算等等)
等程序執(zhí)行完畢后,就會(huì)返回一個(gè)http響應(yīng)包(一般這一步也會(huì)經(jīng)過(guò)多層封裝)
然后就是將這個(gè)包從后端發(fā)送到前端,完成交互
后臺(tái)和前臺(tái)的http交互前后端交互時(shí),http報(bào)文作為信息的載體
所以http是一塊很重要的內(nèi)容,這一部分重點(diǎn)介紹它
http報(bào)文結(jié)構(gòu)報(bào)文一般包括了:通用頭部,請(qǐng)求/響應(yīng)頭部,請(qǐng)求/響應(yīng)體
通用頭部
這也是開(kāi)發(fā)人員見(jiàn)過(guò)的最多的信息,包括如下:
Request Url: 請(qǐng)求的web服務(wù)器地址 Request Method: 請(qǐng)求方式 (Get、POST、OPTIONS、PUT、HEAD、DELETE、CONNECT、TRACE) Status Code: 請(qǐng)求的返回狀態(tài)碼,如200代表成功 Remote Address: 請(qǐng)求的遠(yuǎn)程服務(wù)器地址(會(huì)轉(zhuǎn)為IP)
譬如,在跨域拒絕時(shí),可能是method為options,狀態(tài)碼為404/405等(當(dāng)然,實(shí)際上可能的組合有很多)
其中,Method的話一般分為兩批次:
HTTP1.0定義了三種請(qǐng)求方法: GET, POST 和 HEAD方法。 以及幾種Additional Request Methods:PUT、DELETE、LINK、UNLINK HTTP1.1定義了八種請(qǐng)求方法:GET、POST、HEAD、OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
HTTP 1.0定義參考:https://tools.ietf.org/html/rfc1945
HTTP 1.1定義參考:https://tools.ietf.org/html/rfc2616
這里面最常用到的就是狀態(tài)碼,很多時(shí)候都是通過(guò)狀態(tài)碼來(lái)判斷,如(列舉幾個(gè)最常見(jiàn)的):
200——表明該請(qǐng)求被成功地完成,所請(qǐng)求的資源發(fā)送回客戶端 304——自從上次請(qǐng)求后,請(qǐng)求的網(wǎng)頁(yè)未修改過(guò),請(qǐng)客戶端使用本地緩存 400——客戶端請(qǐng)求有錯(cuò)(譬如可以是安全模塊攔截) 401——請(qǐng)求未經(jīng)授權(quán) 403——禁止訪問(wèn)(譬如可以是未登錄時(shí)禁止) 404——資源未找到 500——服務(wù)器內(nèi)部錯(cuò)誤 503——服務(wù)不可用 ...
再列舉下大致不同范圍狀態(tài)的意義
1xx——指示信息,表示請(qǐng)求已接收,繼續(xù)處理 2xx——成功,表示請(qǐng)求已被成功接收、理解、接受 3xx——重定向,要完成請(qǐng)求必須進(jìn)行更進(jìn)一步的操作 4xx——客戶端錯(cuò)誤,請(qǐng)求有語(yǔ)法錯(cuò)誤或請(qǐng)求無(wú)法實(shí)現(xiàn) 5xx——服務(wù)器端錯(cuò)誤,服務(wù)器未能實(shí)現(xiàn)合法的請(qǐng)求
總之,當(dāng)請(qǐng)求出錯(cuò)時(shí),狀態(tài)碼能幫助快速定位問(wèn)題,完整版本的狀態(tài)可以自行去互聯(lián)網(wǎng)搜索
請(qǐng)求/響應(yīng)頭部
請(qǐng)求和響應(yīng)頭部也是分析時(shí)常用到的
常用的請(qǐng)求頭部(部分):
Accept: 接收類型,表示瀏覽器支持的MIME類型 (對(duì)標(biāo)服務(wù)端返回的Content-Type) Accept-Encoding:瀏覽器支持的壓縮類型,如gzip等,超出類型不能接收 Content-Type:客戶端發(fā)送出去實(shí)體內(nèi)容的類型 Cache-Control: 指定請(qǐng)求和響應(yīng)遵循的緩存機(jī)制,如no-cache If-Modified-Since:對(duì)應(yīng)服務(wù)端的Last-Modified,用來(lái)匹配看文件是否變動(dòng),只能精確到1s之內(nèi),http1.0中 Expires:緩存控制,在這個(gè)時(shí)間內(nèi)不會(huì)請(qǐng)求,直接使用緩存,http1.0,而且是服務(wù)端時(shí)間 Max-age:代表資源在本地緩存多少秒,有效時(shí)間內(nèi)不會(huì)請(qǐng)求,而是使用緩存,http1.1中 If-None-Match:對(duì)應(yīng)服務(wù)端的ETag,用來(lái)匹配文件內(nèi)容是否改變(非常精確),http1.1中 Cookie: 有cookie并且同域訪問(wèn)時(shí)會(huì)自動(dòng)帶上 Connection: 當(dāng)瀏覽器與服務(wù)器通信時(shí)對(duì)于長(zhǎng)連接如何進(jìn)行處理,如keep-alive Host:請(qǐng)求的服務(wù)器URL Origin:最初的請(qǐng)求是從哪里發(fā)起的(只會(huì)精確到端口),Origin比Referer更尊重隱私 Referer:該頁(yè)面的來(lái)源URL(適用于所有類型的請(qǐng)求,會(huì)精確到詳細(xì)頁(yè)面地址,csrf攔截常用到這個(gè)字段) User-Agent:用戶客戶端的一些必要信息,如UA頭部等
常用的響應(yīng)頭部(部分):
Access-Control-Allow-Headers: 服務(wù)器端允許的請(qǐng)求Headers Access-Control-Allow-Methods: 服務(wù)器端允許的請(qǐng)求方法 Access-Control-Allow-Origin: 服務(wù)器端允許的請(qǐng)求Origin頭部(譬如為*) Content-Type:服務(wù)端返回的實(shí)體內(nèi)容的類型 Date:數(shù)據(jù)從服務(wù)器發(fā)送的時(shí)間 Cache-Control:告訴瀏覽器或其他客戶,什么環(huán)境可以安全的緩存文檔 Last-Modified:請(qǐng)求資源的最后修改時(shí)間 Expires:應(yīng)該在什么時(shí)候認(rèn)為文檔已經(jīng)過(guò)期,從而不再緩存它 Max-age:客戶端的本地資源應(yīng)該緩存多少秒,開(kāi)啟了Cache-Control后有效 ETag:請(qǐng)求變量的實(shí)體標(biāo)簽的當(dāng)前值 Set-Cookie:設(shè)置和頁(yè)面關(guān)聯(lián)的cookie,服務(wù)器通過(guò)這個(gè)頭部把cookie傳給客戶端 Keep-Alive:如果客戶端有keep-alive,服務(wù)端也會(huì)有響應(yīng)(如timeout=38) Server:服務(wù)器的一些相關(guān)信息
一般來(lái)說(shuō),請(qǐng)求頭部和響應(yīng)頭部是匹配分析的。
譬如,請(qǐng)求頭部的Accept要和響應(yīng)頭部的Content-Type匹配,否則會(huì)報(bào)錯(cuò)
譬如,跨域請(qǐng)求時(shí),請(qǐng)求頭部的Origin要匹配響應(yīng)頭部的Access-Control-Allow-Origin,否則會(huì)報(bào)跨域錯(cuò)誤
譬如,在使用緩存時(shí),請(qǐng)求頭部的If-Modified-Since、If-None-Match分別和響應(yīng)頭部的Last-Modified、ETag對(duì)應(yīng)
還有很多的分析方法,這里不一一贅述
請(qǐng)求/響應(yīng)實(shí)體
http請(qǐng)求時(shí),除了頭部,還有消息實(shí)體,一般來(lái)說(shuō)
請(qǐng)求實(shí)體中會(huì)將一些需要的參數(shù)都放入進(jìn)入(用于post請(qǐng)求)。
譬如實(shí)體中可以放參數(shù)的序列化形式(a=1&b=2這種),或者直接放表單對(duì)象(Form Data對(duì)象,上傳時(shí)可以?shī)A雜參數(shù)以及文件),等等
而一般響應(yīng)實(shí)體中,就是放服務(wù)端需要傳給客戶端的內(nèi)容
一般現(xiàn)在的接口請(qǐng)求時(shí),實(shí)體中就是對(duì)于的信息的json格式,而像頁(yè)面請(qǐng)求這種,里面就是直接放了一個(gè)html字符串,然后瀏覽器自己解析并渲染。
CRLF
CRLF(Carriage-Return Line-Feed),意思是回車換行,一般作為分隔符存在
請(qǐng)求頭和實(shí)體消息之間有一個(gè)CRLF分隔,響應(yīng)頭部和響應(yīng)實(shí)體之間用一個(gè)CRLF分隔
一般來(lái)說(shuō)(分隔符類別):
CRLF->Windows-style LF->Unix Style CR->Mac Style
如下圖是對(duì)某請(qǐng)求的http報(bào)文結(jié)構(gòu)的簡(jiǎn)要分析
cookie以及優(yōu)化cookie是瀏覽器的一種本地存儲(chǔ)方式,一般用來(lái)幫助客戶端和服務(wù)端通信的,常用來(lái)進(jìn)行身份校驗(yàn),結(jié)合服務(wù)端的session使用。
場(chǎng)景如下(簡(jiǎn)述):
在登陸頁(yè)面,用戶登陸了 此時(shí),服務(wù)端會(huì)生成一個(gè)session,session中有對(duì)于用戶的信息(如用戶名、密碼等) 然后會(huì)有一個(gè)sessionid(相當(dāng)于是服務(wù)端的這個(gè)session對(duì)應(yīng)的key) 然后服務(wù)端在登錄頁(yè)面中寫(xiě)入cookie,值就是:jsessionid=xxx 然后瀏覽器本地就有這個(gè)cookie了,以后訪問(wèn)同域名下的頁(yè)面時(shí),自動(dòng)帶上cookie,自動(dòng)檢驗(yàn),在有效時(shí)間內(nèi)無(wú)需二次登陸。
上述就是cookie的常用場(chǎng)景簡(jiǎn)述(當(dāng)然了,實(shí)際情況下得考慮更多因素)
一般來(lái)說(shuō),cookie是不允許存放敏感信息的(千萬(wàn)不要明文存儲(chǔ)用戶名、密碼),因?yàn)榉浅2话踩?,如果一定要?qiáng)行存儲(chǔ),首先,一定要在cookie中設(shè)置httponly(這樣就無(wú)法通過(guò)js操作了),另外可以考慮rsa等非對(duì)稱加密(因?yàn)閷?shí)際上,瀏覽器本地也是容易被攻克的,并不安全)
另外,由于在同域名的資源請(qǐng)求時(shí),瀏覽器會(huì)默認(rèn)帶上本地的cookie,針對(duì)這種情況,在某些場(chǎng)景下是需要優(yōu)化的。
譬如以下場(chǎng)景:
客戶端在域名A下有cookie(這個(gè)可以是登陸時(shí)由服務(wù)端寫(xiě)入的) 然后在域名A下有一個(gè)頁(yè)面,頁(yè)面中有很多依賴的靜態(tài)資源(都是域名A的,譬如有20個(gè)靜態(tài)資源) 此時(shí)就有一個(gè)問(wèn)題,頁(yè)面加載,請(qǐng)求這些靜態(tài)資源時(shí),瀏覽器會(huì)默認(rèn)帶上cookie 也就是說(shuō),這20個(gè)靜態(tài)資源的http請(qǐng)求,每一個(gè)都得帶上cookie,而實(shí)際上靜態(tài)資源并不需要cookie驗(yàn)證 此時(shí)就造成了較為嚴(yán)重的浪費(fèi),而且也降低了訪問(wèn)速度(因?yàn)閮?nèi)容更多了)
當(dāng)然了,針對(duì)這種場(chǎng)景,是有優(yōu)化方案的(多域名拆分)。具體做法就是:
將靜態(tài)資源分組,分別放到不同的域名下(如static.base.com)
而page.base.com(頁(yè)面所在域名)下請(qǐng)求時(shí),是不會(huì)帶上static.base.com域名的cookie的,所以就避免了浪費(fèi)
說(shuō)到了多域名拆分,這里再提一個(gè)問(wèn)題,那就是:
在移動(dòng)端,如果請(qǐng)求的域名數(shù)過(guò)多,會(huì)降低請(qǐng)求速度(因?yàn)橛蛎捉馕隽鞒淌呛芎馁M(fèi)時(shí)間的,而且移動(dòng)端一般帶寬都比不上pc)
此時(shí)就需要用到一種優(yōu)化方案:dns-prefetch(讓瀏覽器空閑時(shí)提前解析dns域名,不過(guò)也請(qǐng)合理使用,勿濫用)
關(guān)于cookie的交互,可以看下圖總結(jié)
gzip壓縮首先,明確gzip是一種壓縮格式,需要瀏覽器支持才有效(不過(guò)一般現(xiàn)在瀏覽器都支持),
而且gzip壓縮效率很好(高達(dá)70%左右)
然后gzip一般是由apache、tomcat等web服務(wù)器開(kāi)啟
當(dāng)然服務(wù)器除了gzip外,也還會(huì)有其它壓縮格式(如deflate,沒(méi)有g(shù)zip高效,且不流行)
所以一般只需要在服務(wù)器上開(kāi)啟了gzip壓縮,然后之后的請(qǐng)求就都是基于gzip壓縮格式的,
非常方便。
首先看tcp/ip層面的定義:
長(zhǎng)連接:一個(gè)tcp/ip連接上可以連續(xù)發(fā)送多個(gè)數(shù)據(jù)包,在tcp連接保持期間,如果沒(méi)有數(shù)據(jù)包發(fā)送,需要雙方發(fā)檢測(cè)包以維持此連接,一般需要自己做在線維持(類似于心跳包)
短連接:通信雙方有數(shù)據(jù)交互時(shí),就建立一個(gè)tcp連接,數(shù)據(jù)發(fā)送完成后,則斷開(kāi)此tcp連接
然后在http層面:
http1.0中,默認(rèn)使用的是短連接,也就是說(shuō),瀏覽器沒(méi)進(jìn)行一次http操作,就建立一次連接,任務(wù)結(jié)束就中斷連接,譬如每一個(gè)靜態(tài)資源請(qǐng)求時(shí)都是一個(gè)多帶帶的連接
http1.1起,默認(rèn)使用長(zhǎng)連接,使用長(zhǎng)連接會(huì)有這一行Connection: keep-alive,在長(zhǎng)連接的情況下,當(dāng)一個(gè)網(wǎng)頁(yè)打開(kāi)完成后,客戶端和服務(wù)端之間用于傳輸http的tcp連接不會(huì)關(guān)閉,如果客戶端再次訪問(wèn)這個(gè)服務(wù)器的頁(yè)面,會(huì)繼續(xù)使用這一條已經(jīng)建立的連接
注意: keep-alive不會(huì)永遠(yuǎn)保持,它有一個(gè)持續(xù)時(shí)間,一般在服務(wù)器中配置(如apache),另外長(zhǎng)連接需要客戶端和服務(wù)器都支持時(shí)才有效
http 2.0http2.0不是https,它相當(dāng)于是http的下一代規(guī)范(譬如https的請(qǐng)求可以是http2.0規(guī)范的)
然后簡(jiǎn)述下http2.0與http1.1的顯著不同點(diǎn):
http1.1中,每請(qǐng)求一個(gè)資源,都是需要開(kāi)啟一個(gè)tcp/ip連接的,所以對(duì)應(yīng)的結(jié)果是,每一個(gè)資源對(duì)應(yīng)一個(gè)tcp/ip請(qǐng)求,由于tcp/ip本身有并發(fā)數(shù)限制,所以當(dāng)資源一多,速度就顯著慢下來(lái)
http2.0中,一個(gè)tcp/ip請(qǐng)求可以請(qǐng)求多個(gè)資源,也就是說(shuō),只要一次tcp/ip請(qǐng)求,就可以請(qǐng)求若干個(gè)資源,分割成更小的幀請(qǐng)求,速度明顯提升。
所以,如果http2.0全面應(yīng)用,很多http1.1中的優(yōu)化方案就無(wú)需用到了(譬如打包成精靈圖,靜態(tài)資源多域名拆分等)
然后簡(jiǎn)述下http2.0的一些特性:
多路復(fù)用(即一個(gè)tcp/ip連接可以請(qǐng)求多個(gè)資源)
首部壓縮(http頭部壓縮,減少體積)
二進(jìn)制分幀(在應(yīng)用層跟傳送層之間增加了一個(gè)二進(jìn)制分幀層,改進(jìn)傳輸性能,實(shí)現(xiàn)低延遲和高吞吐量)
服務(wù)器端推送(服務(wù)端可以對(duì)客戶端的一個(gè)請(qǐng)求發(fā)出多個(gè)響應(yīng),可以主動(dòng)通知客戶端)
請(qǐng)求優(yōu)先級(jí)(如果流被賦予了優(yōu)先級(jí),它就會(huì)基于這個(gè)優(yōu)先級(jí)來(lái)處理,由服務(wù)器決定需要多少資源來(lái)處理該請(qǐng)求。)
httpshttps就是安全版本的http,譬如一些支付等操作基本都是基于https的,因?yàn)閔ttp請(qǐng)求的安全系數(shù)太低了。
簡(jiǎn)單來(lái)看,https與http的區(qū)別就是: 在請(qǐng)求前,會(huì)建立ssl鏈接,確保接下來(lái)的通信都是加密的,無(wú)法被輕易截取分析
一般來(lái)說(shuō),如果要將網(wǎng)站升級(jí)成https,需要后端支持(后端需要申請(qǐng)證書(shū)等),然后https的開(kāi)銷也比http要大(因?yàn)樾枰~外建立安全鏈接以及加密等),所以一般來(lái)說(shuō)http2.0配合https的體驗(yàn)更佳(因?yàn)閔ttp2.0更快了)
一般來(lái)說(shuō),主要關(guān)注的就是SSL/TLS的握手流程,如下(簡(jiǎn)述):
1. 瀏覽器請(qǐng)求建立SSL鏈接,并向服務(wù)端發(fā)送一個(gè)隨機(jī)數(shù)–Client random和客戶端支持的加密方法,比如RSA加密,此時(shí)是明文傳輸。 2. 服務(wù)端從中選出一組加密算法與Hash算法,回復(fù)一個(gè)隨機(jī)數(shù)–Server random,并將自己的身份信息以證書(shū)的形式發(fā)回給瀏覽器 (證書(shū)里包含了網(wǎng)站地址,非對(duì)稱加密的公鑰,以及證書(shū)頒發(fā)機(jī)構(gòu)等信息) 3. 瀏覽器收到服務(wù)端的證書(shū)后 - 驗(yàn)證證書(shū)的合法性(頒發(fā)機(jī)構(gòu)是否合法,證書(shū)中包含的網(wǎng)址是否和正在訪問(wèn)的一樣),如果證書(shū)信任,則瀏覽器會(huì)顯示一個(gè)小鎖頭,否則會(huì)有提示 - 用戶接收證書(shū)后(不管信不信任),瀏覽會(huì)生產(chǎn)新的隨機(jī)數(shù)–Premaster secret,然后證書(shū)中的公鑰以及指定的加密方法加密`Premaster secret`,發(fā)送給服務(wù)器。 - 利用Client random、Server random和Premaster secret通過(guò)一定的算法生成HTTP鏈接數(shù)據(jù)傳輸?shù)膶?duì)稱加密key-`session key` - 使用約定好的HASH算法計(jì)算握手消息,并使用生成的`session key`對(duì)消息進(jìn)行加密,最后將之前生成的所有信息發(fā)送給服務(wù)端。 4. 服務(wù)端收到瀏覽器的回復(fù) - 利用已知的加解密方式與自己的私鑰進(jìn)行解密,獲取`Premaster secret` - 和瀏覽器相同規(guī)則生成`session key` - 使用`session key`解密瀏覽器發(fā)來(lái)的握手消息,并驗(yàn)證Hash是否與瀏覽器發(fā)來(lái)的一致 - 使用`session key`加密一段握手消息,發(fā)送給瀏覽器 5. 瀏覽器解密并計(jì)算握手消息的HASH,如果與服務(wù)端發(fā)來(lái)的HASH一致,此時(shí)握手過(guò)程結(jié)束,
之后所有的https通信數(shù)據(jù)將由之前瀏覽器生成的session key并利用對(duì)稱加密算法進(jìn)行加密
這里放一張圖(來(lái)源:阮一峰-圖解SSL/TLS協(xié)議)
多帶帶拎出來(lái)的緩存問(wèn)題,http的緩存前后端的http交互中,使用緩存能很大程度上的提升效率,而且基本上對(duì)性能有要求的前端項(xiàng)目都是必用緩存的
強(qiáng)緩存與弱緩存緩存可以簡(jiǎn)單的劃分成兩種類型:強(qiáng)緩存(200 from cache)與協(xié)商緩存(304)
區(qū)別簡(jiǎn)述如下:
強(qiáng)緩存(200 from cache)時(shí),瀏覽器如果判斷本地緩存未過(guò)期,就直接使用,無(wú)需發(fā)起http請(qǐng)求
協(xié)商緩存(304)時(shí),瀏覽器會(huì)向服務(wù)端發(fā)起http請(qǐng)求,然后服務(wù)端告訴瀏覽器文件未改變,讓瀏覽器使用本地緩存
對(duì)于協(xié)商緩存,使用Ctrl + F5強(qiáng)制刷新可以使得緩存無(wú)效
但是對(duì)于強(qiáng)緩存,在未過(guò)期時(shí),必須更新資源路徑才能發(fā)起新的請(qǐng)求(更改了路徑相當(dāng)于是另一個(gè)資源了,這也是前端工程化中常用到的技巧)
緩存頭部簡(jiǎn)述上述提到了強(qiáng)緩存和協(xié)商緩存,那它們是怎么區(qū)分的呢?
答案是通過(guò)不同的http頭部控制
先看下這幾個(gè)頭部:
If-None-Match/E-tag、If-Modified-Since/Last-Modified、Cache-Control/Max-Age、Pragma/Expires
這些就是緩存中常用到的頭部,這里不展開(kāi)。僅列舉下大致使用。
屬于強(qiáng)緩存控制的:
(http1.1)Cache-Control/Max-Age (http1.0)Pragma/Expires
注意:Max-Age不是一個(gè)頭部,它是Cache-Control頭部的值
屬于協(xié)商緩存控制的:
(http1.1)If-None-Match/E-tag (http1.0)If-Modified-Since/Last-Modified
可以看到,上述有提到http1.1和http1.0,這些不同的頭部是屬于不同http時(shí)期的
再提一點(diǎn),其實(shí)HTML頁(yè)面中也有一個(gè)meta標(biāo)簽可以控制緩存方案-Pragma
不過(guò),這種方案還是比較少用到,因?yàn)橹С智闆r不佳,譬如緩存代理服務(wù)器肯定不支持,所以不推薦
頭部的區(qū)別首先明確,http的發(fā)展是從http1.0到http1.1
而在http1.1中,出了一些新內(nèi)容,彌補(bǔ)了http1.0的不足。
http1.0中的緩存控制:
Pragma:嚴(yán)格來(lái)說(shuō),它不屬于專門(mén)的緩存控制頭部,但是它設(shè)置no-cache時(shí)可以讓本地強(qiáng)緩存失效(屬于編譯控制,來(lái)實(shí)現(xiàn)特定的指令,主要是因?yàn)榧嫒輍ttp1.0,所以以前又被大量應(yīng)用)
Expires:服務(wù)端配置的,屬于強(qiáng)緩存,用來(lái)控制在規(guī)定的時(shí)間之前,瀏覽器不會(huì)發(fā)出請(qǐng)求,而是直接使用本地緩存,注意,Expires一般對(duì)應(yīng)服務(wù)器端時(shí)間,如Expires:Fri, 30 Oct 1998 14:19:41
If-Modified-Since/Last-Modified:這兩個(gè)是成對(duì)出現(xiàn)的,屬于協(xié)商緩存的內(nèi)容,其中瀏覽器的頭部是If-Modified-Since,而服務(wù)端的是Last-Modified,它的作用是,在發(fā)起請(qǐng)求時(shí),如果If-Modified-Since和Last-Modified匹配,那么代表服務(wù)器資源并未改變,因此服務(wù)端不會(huì)返回資源實(shí)體,而是只返回頭部,通知瀏覽器可以使用本地緩存。Last-Modified,顧名思義,指的是文件最后的修改時(shí)間,而且只能精確到1s以內(nèi)
http1.1中的緩存控制:
Cache-Control:緩存控制頭部,有no-cache、max-age等多種取值
Max-Age:服務(wù)端配置的,用來(lái)控制強(qiáng)緩存,在規(guī)定的時(shí)間之內(nèi),瀏覽器無(wú)需發(fā)出請(qǐng)求,直接使用本地緩存,注意,Max-Age是Cache-Control頭部的值,不是獨(dú)立的頭部,譬如Cache-Control: max-age=3600,而且它值得是絕對(duì)時(shí)間,由瀏覽器自己計(jì)算
If-None-Match/E-tag:這兩個(gè)是成對(duì)出現(xiàn)的,屬于協(xié)商緩存的內(nèi)容,其中瀏覽器的頭部是If-None-Match,而服務(wù)端的是E-tag,同樣,發(fā)出請(qǐng)求后,如果If-None-Match和E-tag匹配,則代表內(nèi)容未變,通知瀏覽器使用本地緩存,和Last-Modified不同,E-tag更精確,它是類似于指紋一樣的東西,基于FileEtag INode Mtime Size生成,也就是說(shuō),只要文件變,指紋就會(huì)變,而且沒(méi)有1s精確度的限制。
Max-Age相比Expires?
Expires使用的是服務(wù)器端的時(shí)間
但是有時(shí)候會(huì)有這樣一種情況-客戶端時(shí)間和服務(wù)端不同步
那這樣,可能就會(huì)出問(wèn)題了,造成了瀏覽器本地的緩存無(wú)用或者一直無(wú)法過(guò)期
所以一般http1.1后不推薦使用Expires
而Max-Age使用的是客戶端本地時(shí)間的計(jì)算,因此不會(huì)有這個(gè)問(wèn)題
因此推薦使用Max-Age。
注意,如果同時(shí)啟用了Cache-Control與Expires,Cache-Control優(yōu)先級(jí)高。
E-tag相比Last-Modified?
Last-Modified:
表明服務(wù)端的文件最后何時(shí)改變的
它有一個(gè)缺陷就是只能精確到1s,
然后還有一個(gè)問(wèn)題就是有的服務(wù)端的文件會(huì)周期性的改變,導(dǎo)致緩存失效
而E-tag:
是一種指紋機(jī)制,代表文件相關(guān)指紋
只有文件變才會(huì)變,也只要文件變就會(huì)變,
也沒(méi)有精確時(shí)間的限制,只要文件一遍,立馬E-tag就不一樣了
如果同時(shí)帶有E-tag和Last-Modified,服務(wù)端會(huì)優(yōu)先檢查E-tag
各大緩存頭部的整體關(guān)系如下圖
解析頁(yè)面流程前面有提到http交互,那么接下來(lái)就是瀏覽器獲取到html,然后解析,渲染
這部分很多都參考了網(wǎng)上資源,特別是圖片,參考了來(lái)源中的文章
流程簡(jiǎn)述瀏覽器內(nèi)核拿到內(nèi)容后,渲染步驟大致可以分為以下幾步:
1. 解析HTML,構(gòu)建DOM樹(shù) 2. 解析CSS,生成CSS規(guī)則樹(shù) 3. 合并DOM樹(shù)和CSS規(guī)則,生成render樹(shù) 4. 布局render樹(shù)(Layout/reflow),負(fù)責(zé)各元素尺寸、位置的計(jì)算 5. 繪制render樹(shù)(paint),繪制頁(yè)面像素信息 6. 瀏覽器會(huì)將各層的信息發(fā)送給GPU,GPU會(huì)將各層合成(composite),顯示在屏幕上
如下圖:
HTML解析,構(gòu)建DOM整個(gè)渲染步驟中,HTML解析是第一步。
簡(jiǎn)單的理解,這一步的流程是這樣的:瀏覽器解析HTML,構(gòu)建DOM樹(shù)。
但實(shí)際上,在分析整體構(gòu)建時(shí),卻不能一筆帶過(guò),得稍微展開(kāi)。
解析HTML到構(gòu)建出DOM當(dāng)然過(guò)程可以簡(jiǎn)述如下:
Bytes → characters → tokens → nodes → DOM
譬如假設(shè)有這樣一個(gè)HTML頁(yè)面:(以下部分的內(nèi)容出自參考來(lái)源,修改了下格式)
Critical Path Hello web performance students!
瀏覽器的處理如下:
列舉其中的一些重點(diǎn)過(guò)程:
1. Conversion轉(zhuǎn)換:瀏覽器將獲得的HTML內(nèi)容(Bytes)基于他的編碼轉(zhuǎn)換為單個(gè)字符 2. Tokenizing分詞:瀏覽器按照HTML規(guī)范標(biāo)準(zhǔn)將這些字符轉(zhuǎn)換為不同的標(biāo)記token。每個(gè)token都有自己獨(dú)特的含義以及規(guī)則集 3. Lexing詞法分析:分詞的結(jié)果是得到一堆的token,此時(shí)把他們轉(zhuǎn)換為對(duì)象,這些對(duì)象分別定義他們的屬性和規(guī)則 4. DOM構(gòu)建:因?yàn)镠TML標(biāo)記定義的就是不同標(biāo)簽之間的關(guān)系,這個(gè)關(guān)系就像是一個(gè)樹(shù)形結(jié)構(gòu)一樣 例如:body對(duì)象的父節(jié)點(diǎn)就是HTML對(duì)象,然后段略p對(duì)象的父節(jié)點(diǎn)就是body對(duì)象
最后的DOM樹(shù)如下:
生成CSS規(guī)則同理,CSS規(guī)則樹(shù)的生成也是類似。簡(jiǎn)述為:
Bytes → characters → tokens → nodes → CSSOM
譬如style.css內(nèi)容如下:
body { font-size: 16px } p { font-weight: bold } span { color: red } p span { display: none } img { float: right }
那么最終的CSSOM樹(shù)就是:
構(gòu)建渲染樹(shù)當(dāng)DOM樹(shù)和CSSOM都有了后,就要開(kāi)始構(gòu)建渲染樹(shù)了
一般來(lái)說(shuō),渲染樹(shù)和DOM樹(shù)相對(duì)應(yīng)的,但不是嚴(yán)格意義上的一一對(duì)應(yīng)
因?yàn)橛幸恍┎豢梢?jiàn)的DOM元素不會(huì)插入到渲染樹(shù)中,如head這種不可見(jiàn)的標(biāo)簽或者display: none等
整體來(lái)說(shuō)可以看圖:
渲染有了render樹(shù),接下來(lái)就是開(kāi)始渲染,基本流程如下:
圖中重要的四個(gè)步驟就是:
1. 計(jì)算CSS樣式 2. 構(gòu)建渲染樹(shù) 3. 布局,主要定位坐標(biāo)和大小,是否換行,各種position overflow z-index屬性 4. 繪制,將圖像繪制出來(lái)
然后,圖中的線與箭頭代表通過(guò)js動(dòng)態(tài)修改了DOM或CSS,導(dǎo)致了重新布局(Layout)或渲染(Repaint)
這里L(fēng)ayout和Repaint的概念是有區(qū)別的:
Layout,也稱為Reflow,即回流。一般意味著元素的內(nèi)容、結(jié)構(gòu)、位置或尺寸發(fā)生了變化,需要重新計(jì)算樣式和渲染樹(shù)
Repaint,即重繪。意味著元素發(fā)生的改變只是影響了元素的一些外觀之類的時(shí)候(例如,背景色,邊框顏色,文字顏色等),此時(shí)只需要應(yīng)用新樣式繪制這個(gè)元素就可以了
回流的成本開(kāi)銷要高于重繪,而且一個(gè)節(jié)點(diǎn)的回流往往回導(dǎo)致子節(jié)點(diǎn)以及同級(jí)節(jié)點(diǎn)的回流,
所以優(yōu)化方案中一般都包括,盡量避免回流。
什么會(huì)引起回流?
1.頁(yè)面渲染初始化 2.DOM結(jié)構(gòu)改變,比如刪除了某個(gè)節(jié)點(diǎn) 3.render樹(shù)變化,比如減少了padding 4.窗口resize 5.最復(fù)雜的一種:獲取某些屬性,引發(fā)回流, 很多瀏覽器會(huì)對(duì)回流做優(yōu)化,會(huì)等到數(shù)量足夠時(shí)做一次批處理回流, 但是除了render樹(shù)的直接變化,當(dāng)獲取一些屬性時(shí),瀏覽器為了獲得正確的值也會(huì)觸發(fā)回流,這樣使得瀏覽器優(yōu)化無(wú)效,包括 (1)offset(Top/Left/Width/Height) (2) scroll(Top/Left/Width/Height) (3) cilent(Top/Left/Width/Height) (4) width,height (5) 調(diào)用了getComputedStyle()或者IE的currentStyle
回流一定伴隨著重繪,重繪卻可以多帶帶出現(xiàn)
所以一般會(huì)有一些優(yōu)化方案,如:
減少逐項(xiàng)更改樣式,最好一次性更改style,或者將樣式定義為class并一次性更新
避免循環(huán)操作dom,創(chuàng)建一個(gè)documentFragment或div,在它上面應(yīng)用所有DOM操作,最后再把它添加到window.document
避免多次讀取offset等屬性。無(wú)法避免則將它們緩存到變量
將復(fù)雜的元素絕對(duì)定位或固定定位,使得它脫離文檔流,否則回流代價(jià)會(huì)很高
注意:改變字體大小會(huì)引發(fā)回流
再來(lái)看一個(gè)示例:
var s = document.body.style; s.padding = "2px"; // 回流+重繪 s.border = "1px solid red"; // 再一次 回流+重繪 s.color = "blue"; // 再一次重繪 s.backgroundColor = "#ccc"; // 再一次 重繪 s.fontSize = "14px"; // 再一次 回流+重繪 // 添加node,再一次 回流+重繪 document.body.appendChild(document.createTextNode("abc!"));簡(jiǎn)單層與復(fù)合層
上述中的渲染中止步于繪制,但實(shí)際上繪制這一步也沒(méi)有這么簡(jiǎn)單,它可以結(jié)合復(fù)合層和簡(jiǎn)單層的概念來(lái)講。
這里不展開(kāi),進(jìn)簡(jiǎn)單介紹下:
可以認(rèn)為默認(rèn)只有一個(gè)復(fù)合圖層,所有的DOM節(jié)點(diǎn)都是在這個(gè)復(fù)合圖層下的
如果開(kāi)啟了硬件加速功能,可以將某個(gè)節(jié)點(diǎn)變成復(fù)合圖層
復(fù)合圖層之間的繪制互不干擾,由GPU直接控制
而簡(jiǎn)單圖層中,就算是absolute等布局,變化時(shí)不影響整體的回流,但是由于在同一個(gè)圖層中,仍然是會(huì)影響繪制的,因此做動(dòng)畫(huà)時(shí)性能仍然很低。而復(fù)合層是獨(dú)立的,所以一般做動(dòng)畫(huà)推薦使用硬件加速
更多參考:
普通圖層和復(fù)合圖層
Chrome中的調(diào)試Chrome的開(kāi)發(fā)者工具中,Performance中可以看到詳細(xì)的渲染過(guò)程:
上面介紹了html解析,渲染流程。但實(shí)際上,在解析html時(shí),會(huì)遇到一些資源連接,此時(shí)就需要進(jìn)行多帶帶處理了
簡(jiǎn)單起見(jiàn),這里將遇到的靜態(tài)資源分為一下幾大類(未列舉所有):
CSS樣式資源
JS腳本資源
img圖片類資源
遇到外鏈時(shí)的處理
當(dāng)遇到上述的外鏈時(shí),會(huì)多帶帶開(kāi)啟一個(gè)下載線程去下載資源(http1.1中是每一個(gè)資源的下載都要開(kāi)啟一個(gè)http請(qǐng)求,對(duì)應(yīng)一個(gè)tcp/ip鏈接)
遇到CSS樣式資源
CSS資源的處理有幾個(gè)特點(diǎn):
CSS下載時(shí)異步,不會(huì)阻塞瀏覽器構(gòu)建DOM樹(shù)
但是會(huì)阻塞渲染,也就是在構(gòu)建render時(shí),會(huì)等到css下載解析完畢后才進(jìn)行(這點(diǎn)與瀏覽器優(yōu)化有關(guān),防止css規(guī)則不斷改變,避免了重復(fù)的構(gòu)建)
有例外,media query聲明的CSS是不會(huì)阻塞渲染的
遇到JS腳本資源
JS腳本資源的處理有幾個(gè)特點(diǎn):
阻塞瀏覽器的解析,也就是說(shuō)發(fā)現(xiàn)一個(gè)外鏈腳本時(shí),需等待腳本下載完成并執(zhí)行后才會(huì)繼續(xù)解析HTML
瀏覽器的優(yōu)化,一般現(xiàn)代瀏覽器有優(yōu)化,在腳本阻塞時(shí),也會(huì)繼續(xù)下載其它資源(當(dāng)然有并發(fā)上限),但是雖然腳本可以并行下載,解析過(guò)程仍然是阻塞的,也就是說(shuō)必須這個(gè)腳本執(zhí)行完畢后才會(huì)接下來(lái)的解析,并行下載只是一種優(yōu)化而已
defer與async,普通的腳本是會(huì)阻塞瀏覽器解析的,但是可以加上defer或async屬性,這樣腳本就變成異步了,可以等到解析完畢后再執(zhí)行
注意,defer和async是有區(qū)別的: defer是延遲執(zhí)行,而async是異步執(zhí)行。
簡(jiǎn)單的說(shuō)(不展開(kāi)):
async是異步執(zhí)行,異步下載完畢后就會(huì)執(zhí)行,不確保執(zhí)行順序,一定在onload前,但不確定在DOMContentLoaded事件的前或后
defer是延遲執(zhí)行,在瀏覽器看起來(lái)的效果像是將腳本放在了body后面一樣(雖然按規(guī)范應(yīng)該是在DOMContentLoaded事件前,但實(shí)際上不同瀏覽器的優(yōu)化效果不一樣,也有可能在它后面)
遇到img圖片類資源
遇到圖片等資源時(shí),直接就是異步下載,不會(huì)阻塞解析,下載完畢后直接用圖片替換原有src的地方
loaded和domcontentloaded簡(jiǎn)單的對(duì)比:
DOMContentLoaded 事件觸發(fā)時(shí),僅當(dāng)DOM加載完成,不包括樣式表,圖片(譬如如果有async加載的腳本就不一定完成)
load 事件觸發(fā)時(shí),頁(yè)面上所有的DOM,樣式表,腳本,圖片都已經(jīng)加載完成了
CSS的可視化格式模型這一部分內(nèi)容很多參考《精通CSS-高級(jí)Web標(biāo)準(zhǔn)解決方案》以及參考來(lái)源
前面提到了整體的渲染概念,但實(shí)際上文檔樹(shù)中的元素是按什么渲染規(guī)則渲染的,是可以進(jìn)一步展開(kāi)的,此部分內(nèi)容即: CSS的可視化格式模型
先了解:
CSS中規(guī)定每一個(gè)元素都有自己的盒子模型(相當(dāng)于規(guī)定了這個(gè)元素如何顯示)
然后可視化格式模型則是把這些盒子按照規(guī)則擺放到頁(yè)面上,也就是如何布局
換句話說(shuō),盒子模型規(guī)定了怎么在頁(yè)面里擺放盒子,盒子的相互作用等等
說(shuō)到底: CSS的可視化格式模型就是規(guī)定了瀏覽器在頁(yè)面中如何處理文檔樹(shù)
關(guān)鍵字:
包含塊(Containing Block) 控制框(Controlling Box) BFC(Block Formatting Context) IFC(Inline Formatting Context) 定位體系 浮動(dòng) ...
另外,CSS有三種定位機(jī)制:普通流,浮動(dòng),絕對(duì)定位,如無(wú)特別提及,下文中都是針對(duì)普通流中的
包含塊(Containing Block)一個(gè)元素的box的定位和尺寸,會(huì)與某一矩形框有關(guān),這個(gè)框就稱之為包含塊。
元素會(huì)為它的子孫元素創(chuàng)建包含塊,但是,并不是說(shuō)元素的包含塊就是它的父元素,元素的包含塊與它的祖先元素的樣式等有關(guān)系
譬如:
根元素是最頂端的元素,它沒(méi)有父節(jié)點(diǎn),它的包含塊就是初始包含塊
static和relative的包含塊由它最近的塊級(jí)、單元格或者行內(nèi)塊祖先元素的內(nèi)容框(content)創(chuàng)建
fixed的包含塊是當(dāng)前可視窗口
absolute的包含塊由它最近的position 屬性為absolute、relative或者fixed的祖先元素創(chuàng)建
如果其祖先元素是行內(nèi)元素,則包含塊取決于其祖先元素的direction特性
如果祖先元素不是行內(nèi)元素,那么包含塊的區(qū)域應(yīng)該是祖先元素的內(nèi)邊距邊界
控制框(Controlling Box)塊級(jí)元素和塊框以及行內(nèi)元素和行框的相關(guān)概念
塊框:
塊級(jí)元素會(huì)生成一個(gè)塊框(Block Box),塊框會(huì)占據(jù)一整行,用來(lái)包含子box和生成的內(nèi)容
塊框同時(shí)也是一個(gè)塊包含框(Containing Box),里面要么只包含塊框,要么只包含行內(nèi)框(不能混雜),如果塊框內(nèi)部有塊級(jí)元素也有行內(nèi)元素,那么行內(nèi)元素會(huì)被匿名塊框包圍
關(guān)于匿名塊框的生成,示例:
Some textMore text
div生成了一個(gè)塊框,包含了另一個(gè)塊框p以及文本內(nèi)容Some text,此時(shí)Some text文本會(huì)被強(qiáng)制加到一個(gè)匿名的塊框里面,被div生成的塊框包含(其實(shí)這個(gè)就是IFC中提到的行框,包含這些行內(nèi)框的這一行匿名塊形成的框,行框和行內(nèi)框不同)
換句話說(shuō):
如果一個(gè)塊框在其中包含另外一個(gè)塊框,那么我們強(qiáng)迫它只能包含塊框,因此其它文本內(nèi)容生成出來(lái)的都是匿名塊框(而不是匿名行內(nèi)框)
行內(nèi)框:
一個(gè)行內(nèi)元素生成一個(gè)行內(nèi)框
行內(nèi)元素能排在一行,允許左右有其它元素
關(guān)于匿名行內(nèi)框的生成,示例:
Some emphasized text
P元素生成一個(gè)塊框,其中有幾個(gè)行內(nèi)框(如EM),以及文本Some , text,此時(shí)會(huì)專門(mén)為這些文本生成匿名行內(nèi)框
display屬性的影響
display的幾個(gè)屬性也可以影響不同框的生成:
block,元素生成一個(gè)塊框
inline,元素產(chǎn)生一個(gè)或多個(gè)的行內(nèi)框
inline-block,元素產(chǎn)生一個(gè)行內(nèi)級(jí)塊框,行內(nèi)塊框的內(nèi)部會(huì)被當(dāng)作塊塊來(lái)格式化,而此元素本身會(huì)被當(dāng)作行內(nèi)級(jí)框來(lái)格式化(這也是為什么會(huì)產(chǎn)生BFC)
none,不生成框,不再格式化結(jié)構(gòu)中,當(dāng)然了,另一個(gè)visibility: hidden則會(huì)產(chǎn)生一個(gè)不可見(jiàn)的框
總結(jié):
如果一個(gè)框里,有一個(gè)塊級(jí)元素,那么這個(gè)框里的內(nèi)容都會(huì)被當(dāng)作塊框來(lái)進(jìn)行格式化,因?yàn)橹灰霈F(xiàn)了塊級(jí)元素,就會(huì)將里面的內(nèi)容分塊幾塊,每一塊獨(dú)占一行(出現(xiàn)行內(nèi)可以用匿名塊框解決)
如果一個(gè)框里,沒(méi)有任何塊級(jí)元素,那么這個(gè)框里的內(nèi)容會(huì)被當(dāng)成行內(nèi)框來(lái)格式化,因?yàn)槔锩娴膬?nèi)容是按照順序成行的排列
BFC(Block Formatting Context)FC(格式上下文)?
FC即格式上下文,它定義框內(nèi)部的元素渲染規(guī)則,比較抽象,譬如
FC像是一個(gè)大箱子,里面裝有很多元素 箱子可以隔開(kāi)里面的元素和外面的元素(所以外部并不會(huì)影響FC內(nèi)部的渲染) 內(nèi)部的規(guī)則可以是:如何定位,寬高計(jì)算,margin折疊等等
不同類型的框參與的FC類型不同,譬如塊級(jí)框?qū)?yīng)BFC,行內(nèi)框?qū)?yīng)IFC
注意,并不是說(shuō)所有的框都會(huì)產(chǎn)生FC,而是符合特定條件才會(huì)產(chǎn)生,只有產(chǎn)生了對(duì)應(yīng)的FC后才會(huì)應(yīng)用對(duì)應(yīng)渲染規(guī)則
BFC規(guī)則:
在塊格式化上下文中 每一個(gè)元素左外邊與包含塊的左邊相接觸(對(duì)于從右到左的格式化,右外邊接觸右邊) 即使存在浮動(dòng)也是如此(所以浮動(dòng)元素正常會(huì)直接貼近它的包含塊的左邊,與普通元素重合) 除非這個(gè)元素也創(chuàng)建了一個(gè)新的BFC
總結(jié)幾點(diǎn)BFC特點(diǎn):
內(nèi)部box在垂直方向,一個(gè)接一個(gè)的放置
box的垂直方向由margin決定,屬于同一個(gè)BFC的兩個(gè)box間的margin會(huì)重疊
BFC區(qū)域不會(huì)與float box重疊(可用于排版)
BFC就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器,容器里面的子元素不會(huì)影響到外面的元素。反之也如此
計(jì)算BFC的高度時(shí),浮動(dòng)元素也參與計(jì)算(不會(huì)浮動(dòng)坍塌)
如何觸發(fā)BFC?
根元素
float屬性不為none
position為absolute或fixed
display為inline-block, flex, inline-flex,table,table-cell,table-caption
overflow不為visible
這里提下,display: table,它本身不產(chǎn)生BFC,但是它會(huì)產(chǎn)生匿名框(包含display: table-cell的框),而這個(gè)匿名框產(chǎn)生BFC
更多請(qǐng)自行網(wǎng)上搜索
IFC(Inline Formatting Context)IFC即行內(nèi)框產(chǎn)生的格式上下文
IFC規(guī)則
在行內(nèi)格式化上下文中 框一個(gè)接一個(gè)地水平排列,起點(diǎn)是包含塊的頂部。 水平方向上的 margin,border 和 padding 在框之間得到保留 框在垂直方向上可以以不同的方式對(duì)齊:它們的頂部或底部對(duì)齊,或根據(jù)其中文字的基線對(duì)齊
行框
包含那些框的長(zhǎng)方形區(qū)域,會(huì)形成一行,叫做行框
行框的寬度由它的包含塊和其中的浮動(dòng)元素決定,高度的確定由行高度計(jì)算規(guī)則決定<
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93349.html
摘要:前言一直混跡社區(qū)突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來(lái)有點(diǎn)混亂所以將前端主流技術(shù)做了一個(gè)書(shū)簽整理不求最多最全但求最實(shí)用。 前言 一直混跡社區(qū),突然發(fā)現(xiàn)自己收藏了不少好文但是管理起來(lái)有點(diǎn)混亂; 所以將前端主流技術(shù)做了一個(gè)書(shū)簽整理,不求最多最全,但求最實(shí)用。 書(shū)簽源碼 書(shū)簽導(dǎo)入瀏覽器效果截圖showImg(https://segmentfault.com/img/bVbg41b?w=107...
摘要:接下來(lái)深入的介紹幾種性能優(yōu)化的小最小化重繪和重排既然重排重繪是會(huì)影響頁(yè)面的性能,尤其是糟糕的代碼更會(huì)將重排帶來(lái)的性能問(wèn)題放大。前面有講到,當(dāng)訪問(wèn)諸如,這種屬性時(shí),會(huì)沖破瀏覽器自有的優(yōu)化通過(guò)隊(duì)列化修改和批量運(yùn)行的方法,減少重排重繪版次。 前言,最近利用碎片時(shí)間拜讀了一下尼古拉斯的另一巨作《高性能JavaScript》,今天寫(xiě)的文章從老生常談的頁(yè)面重繪和重排入手,去探究這兩個(gè)概念在頁(yè)面性能...
摘要:詳解十大常用設(shè)計(jì)模式力薦深度好文深入理解大設(shè)計(jì)模式收集各種疑難雜癥的問(wèn)題集錦關(guān)于,工作和學(xué)習(xí)過(guò)程中遇到過(guò)許多問(wèn)題,也解答過(guò)許多別人的問(wèn)題。介紹了的內(nèi)存管理。 延遲加載 (Lazyload) 三種實(shí)現(xiàn)方式 延遲加載也稱為惰性加載,即在長(zhǎng)網(wǎng)頁(yè)中延遲加載圖像。用戶滾動(dòng)到它們之前,視口外的圖像不會(huì)加載。本文詳細(xì)介紹了三種延遲加載的實(shí)現(xiàn)方式。 詳解 Javascript十大常用設(shè)計(jì)模式 力薦~ ...
摘要:通過(guò)管理組件通信通過(guò)驅(qū)動(dòng)視圖比較差異進(jìn)行更新操作作者第七頁(yè)鏈接來(lái)源知乎著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)。達(dá)到無(wú)刷新的效果。對(duì)象的狀態(tài)不受外界影響。對(duì)象代表一個(gè)異步操作,有三種狀態(tài)進(jìn)行中已完成,又稱和已失敗。 以下問(wèn)題解釋非本人原創(chuàng),是根據(jù)面試經(jīng)驗(yàn)整理后覺(jué)得更容易理解的解釋版本,歡迎補(bǔ)充。 一. 輸入url后的加載過(guò)程 從輸入 URL 到頁(yè)面加載完成的過(guò)程中都發(fā)生了什么 計(jì)算機(jī)...
摘要:通過(guò)管理組件通信通過(guò)驅(qū)動(dòng)視圖比較差異進(jìn)行更新操作作者第七頁(yè)鏈接來(lái)源知乎著作權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)。達(dá)到無(wú)刷新的效果。對(duì)象的狀態(tài)不受外界影響。對(duì)象代表一個(gè)異步操作,有三種狀態(tài)進(jìn)行中已完成,又稱和已失敗。 以下問(wèn)題解釋非本人原創(chuàng),是根據(jù)面試經(jīng)驗(yàn)整理后覺(jué)得更容易理解的解釋版本,歡迎補(bǔ)充。 一. 輸入url后的加載過(guò)程 從輸入 URL 到頁(yè)面加載完成的過(guò)程中都發(fā)生了什么 計(jì)算機(jī)...
閱讀 2688·2023-04-25 20:19
閱讀 1953·2021-11-24 09:38
閱讀 1639·2021-11-16 11:44
閱讀 4378·2021-09-02 15:40
閱讀 1359·2019-08-30 15:55
閱讀 2029·2019-08-30 15:52
閱讀 3769·2019-08-29 17:20
閱讀 2281·2019-08-29 13:48