從輸入U(xiǎn)RL到頁(yè)面加載的過(guò)程喉前?如何由一道題完善自己的前端知識(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)求都是單獨(dú)的線程
更多
-
開(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
-
單獨(dú)拎出來(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ú)分配資源煤裙,獨(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. 單獨(dú)拎出來(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)求都是單獨(dú)的線程
每次網(wǎng)絡(luò)請(qǐng)求時(shí)都需要開(kāi)辟單獨(dú)的線程進(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壓縮格式的凡桥, 非常方便蟀伸。
長(zhǎng)連接與短連接
首先看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è)單獨(dú)的連接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.0
http2.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)求。)
https
https就是安全版本的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é)議)
單獨(dú)拎出來(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
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
不過(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)系如下圖
[圖片上傳失敗...(image-541997-1586929835700)]
解析頁(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)源钓瞭,修改了下格式)
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>
瀏覽器的處理如下:
列舉其中的一些重點(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
回流一定伴隨著重繪裹唆,重繪卻可以單獨(dú)出現(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à)推薦使用硬件加速
更多參考:
Chrome中的調(diào)試
Chrome的開(kāi)發(fā)者工具中尼荆,Performance中可以看到詳細(xì)的渲染過(guò)程:
資源外鏈的下載
上面介紹了html解析左腔,渲染流程。但實(shí)際上耀找,在解析html時(shí)翔悠,會(huì)遇到一些資源連接业崖,此時(shí)就需要進(jìn)行單獨(dú)處理了
簡(jiǎn)單起見(jiàn)野芒,這里將遇到的靜態(tài)資源分為一下幾大類(未列舉所有):
CSS樣式資源
JS腳本資源
img圖片類資源
遇到外鏈時(shí)的處理
當(dāng)遇到上述的外鏈時(shí),會(huì)單獨(dú)開(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)于匿名塊框的生成臼隔,示例:
<DIV>
Some text
<P>More text
</DIV>
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)框的生成盛正,示例:
<P>Some <EM>emphasized</EM> text</P>
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ī)則決定
行框的規(guī)則:
如果幾個(gè)行內(nèi)框在水平方向無(wú)法放入一個(gè)行框內(nèi)矮男,它們可以分配在兩個(gè)或多個(gè)垂直堆疊的行框中(即行內(nèi)框的分割)
行框在堆疊時(shí)沒(méi)有垂直方向上的分割且永不重疊
行框的高度總是足夠容納所包含的所有框移必。不過(guò),它可能高于它包含的最高的框(例如昂灵,框?qū)R會(huì)引起基線對(duì)齊)
行框的左邊接觸到其包含塊的左邊避凝,右邊接觸到其包含塊的右邊。
結(jié)合補(bǔ)充下IFC規(guī)則:
浮動(dòng)元素可能會(huì)處于包含塊邊緣和行框邊緣之間
盡管在相同的行內(nèi)格式化上下文中的行框通常擁有相同的寬度(包含塊的寬度)眨补,它們可能會(huì)因浮動(dòng)元素縮短了可用寬度管削,而在寬度上發(fā)生變化
同一行內(nèi)格式化上下文中的行框通常高度不一樣(如,一行包含了一個(gè)高的圖形撑螺,而其它行只包含文本)
當(dāng)一行中行內(nèi)框?qū)挾鹊目偤托∮诎鼈兊男锌虻膶捄迹鼈冊(cè)谒椒较蛏系膶?duì)齊,取決于 `text-align` 特性
空的行內(nèi)框應(yīng)該被忽略
即不包含文本,保留空白符含潘,margin/padding/border非0的行內(nèi)元素饲做,
以及其他常規(guī)流中的內(nèi)容(比如,圖片遏弱,inline blocks 和 inline tables)盆均,
并且不是以換行結(jié)束的行框,
必須被當(dāng)作零高度行框?qū)Υ?
總結(jié):
行內(nèi)元素總是會(huì)應(yīng)用IFC渲染規(guī)則
行內(nèi)元素會(huì)應(yīng)用IFC規(guī)則渲染漱逸,譬如
text-align
可以用來(lái)居中等塊框內(nèi)部泪姨,對(duì)于文本這類的匿名元素,會(huì)產(chǎn)生匿名行框包圍饰抒,而行框內(nèi)部就應(yīng)用IFC渲染規(guī)則
行內(nèi)框內(nèi)部肮砾,對(duì)于那些行內(nèi)元素,一樣應(yīng)用IFC渲染規(guī)則
另外袋坑,
inline-block
仗处,會(huì)在元素外層產(chǎn)生IFC(所以這個(gè)元素是可以通過(guò)text-align
水平居中的),當(dāng)然枣宫,它內(nèi)部則按照BFC規(guī)則渲染
相比BFC規(guī)則來(lái)說(shuō)婆誓,IFC可能更加抽象(因?yàn)闆](méi)有那么條理清晰的規(guī)則和觸發(fā)條件)
但總的來(lái)說(shuō),它就是行內(nèi)元素自身如何顯示以及在框內(nèi)如何擺放的渲染規(guī)則镶柱,這樣描述應(yīng)該更容易理解
其它
當(dāng)然還有有一些其它內(nèi)容:
譬如常規(guī)流旷档,浮動(dòng)模叙,絕對(duì)定位等區(qū)別
譬如浮動(dòng)元素不包含在常規(guī)流中
譬如相對(duì)定位歇拆,絕對(duì)定位,
Fixed
定位等區(qū)別譬如
z-index
的分層顯示機(jī)制等
這里不一一展開(kāi)范咨,更多請(qǐng)參考:
http://bbs.csdn.net/topics/340204423
JS引擎解析過(guò)程
前面有提到遇到JS腳本時(shí)故觅,會(huì)等到它的執(zhí)行,實(shí)際上是需要引擎解析的渠啊,這里展開(kāi)描述(介紹主干流程)
JS的解釋階段
首先得明確: JS是解釋型語(yǔ)音输吏,所以它無(wú)需提前編譯,而是由解釋器實(shí)時(shí)運(yùn)行
引擎對(duì)JS的處理過(guò)程可以簡(jiǎn)述如下:
1. 讀取代碼替蛉,進(jìn)行詞法分析(Lexical analysis)贯溅,然后將代碼分解成詞元(token)
2. 對(duì)詞元進(jìn)行語(yǔ)法分析(parsing),然后將代碼整理成語(yǔ)法樹(shù)(syntax tree)
3. 使用翻譯器(translator)躲查,將代碼轉(zhuǎn)為字節(jié)碼(bytecode)
4. 使用字節(jié)碼解釋器(bytecode interpreter)它浅,將字節(jié)碼轉(zhuǎn)為機(jī)器碼
最終計(jì)算機(jī)執(zhí)行的就是機(jī)器碼。
為了提高運(yùn)行速度镣煮,現(xiàn)代瀏覽器一般采用即時(shí)編譯(JIT-Just In Time compiler
)
即字節(jié)碼只在運(yùn)行時(shí)編譯姐霍,用到哪一行就編譯哪一行,并且把編譯結(jié)果緩存(inline cache
)
這樣整個(gè)程序的運(yùn)行速度能得到顯著提升。
而且镊折,不同瀏覽器策略可能還不同胯府,有的瀏覽器就省略了字節(jié)碼的翻譯步驟,直接轉(zhuǎn)為機(jī)器碼(如chrome的v8)
總結(jié)起來(lái)可以認(rèn)為是: 核心的JIT
編譯器將源碼編譯成機(jī)器碼運(yùn)行
JS的預(yù)處理階段
上述將的是解釋器的整體過(guò)程恨胚,這里再提下在正式執(zhí)行JS前骂因,還會(huì)有一個(gè)預(yù)處理階段 (譬如變量提升,分號(hào)補(bǔ)全等)
預(yù)處理階段會(huì)做一些事情赃泡,確保JS可以正確執(zhí)行侣签,這里僅提部分:
分號(hào)補(bǔ)全
JS執(zhí)行是需要分號(hào)的,但為什么以下語(yǔ)句卻可以正常運(yùn)行呢急迂?
console.log('a')
console.log('b')
原因就是JS解釋器有一個(gè)Semicolon Insertion規(guī)則影所,它會(huì)按照一定規(guī)則,在適當(dāng)?shù)奈恢醚a(bǔ)充分號(hào)
譬如列舉幾條自動(dòng)加分號(hào)的規(guī)則:
當(dāng)有換行符(包括含有換行符的多行注釋)僚碎,并且下一個(gè)
token
沒(méi)法跟前面的語(yǔ)法匹配時(shí)猴娩,會(huì)自動(dòng)補(bǔ)分號(hào)。當(dāng)有
}
時(shí)勺阐,如果缺少分號(hào)卷中,會(huì)補(bǔ)分號(hào)。程序源代碼結(jié)束時(shí)渊抽,如果缺少分號(hào)蟆豫,會(huì)補(bǔ)分號(hào)。
于是懒闷,上述的代碼就變成了
console.log('a');
console.log('b');
所以可以正常運(yùn)行
當(dāng)然了十减,這里有一個(gè)經(jīng)典的例子:
function b() {
return
{
a: 'a'
};
}
由于分號(hào)補(bǔ)全機(jī)制,所以它變成了:
function b() {
return;
{
a: 'a'
};
}
所以運(yùn)行后是undefined
變量提升
一般包括函數(shù)提升和變量提升
譬如:
a = 1;
b();
function b() {
console.log('b');
}
var a;
經(jīng)過(guò)變量提升后愤估,就變成:
function b() {
console.log('b');
}
var a;
a = 1;
b();
這里沒(méi)有展開(kāi)帮辟,其實(shí)展開(kāi)也可以牽涉到很多內(nèi)容的
譬如可以提下變量聲明,函數(shù)聲明玩焰,形參由驹,實(shí)參的優(yōu)先級(jí)順序,以及es6中l(wèi)et有關(guān)的臨時(shí)死區(qū)等
JS的執(zhí)行階段
此階段的內(nèi)容中的圖片來(lái)源:深入理解JavaScript系列(10):JavaScript核心(晉級(jí)高手必讀篇)
解釋器解釋完語(yǔ)法規(guī)則后昔园,就開(kāi)始執(zhí)行蔓榄,然后整個(gè)執(zhí)行流程中大致包含以下概念:
執(zhí)行上下文,執(zhí)行堆棧概念(如全局上下文默刚,當(dāng)前活動(dòng)上下文)
VO(變量對(duì)象)和AO(活動(dòng)對(duì)象)
作用域鏈
this機(jī)制等
這些概念如果深入講解的話內(nèi)容過(guò)多甥郑,因此這里僅提及部分特性
執(zhí)行上下文簡(jiǎn)單解釋
JS有
執(zhí)行上下文
)瀏覽器首次載入腳本,它將創(chuàng)建
全局執(zhí)行上下文
羡棵,并壓入執(zhí)行棧棧頂(不可被彈出)然后每進(jìn)入其它作用域就創(chuàng)建對(duì)應(yīng)的執(zhí)行上下文并把它壓入執(zhí)行棧的頂部
一旦對(duì)應(yīng)的上下文執(zhí)行完畢壹若,就從棧頂彈出,并將上下文控制權(quán)交給當(dāng)前的棧。
這樣依次執(zhí)行(最終都會(huì)回到全局執(zhí)行上下文)
譬如店展,如果程序執(zhí)行完畢养篓,被彈出執(zhí)行棧,然后有沒(méi)有被引用(沒(méi)有形成閉包)赂蕴,那么這個(gè)函數(shù)中用到的內(nèi)存就會(huì)被垃圾處理器自動(dòng)回收
然后執(zhí)行上下文與VO柳弄,作用域鏈,this的關(guān)系是:
每一個(gè)執(zhí)行上下文概说,都有三個(gè)重要屬性:
變量對(duì)象(
Variable object碧注,VO
)作用域鏈(
Scope chain
)this
VO與AO
VO是執(zhí)行上下文的屬性(抽象概念),但是只有全局上下文的變量對(duì)象允許通過(guò)VO的屬性名稱來(lái)間接訪問(wèn)(因?yàn)樵谌稚舷挛睦锾桥猓謱?duì)象自身就是變量對(duì)象)
AO(activation object
)萍丐,當(dāng)函數(shù)被調(diào)用者激活,AO就被創(chuàng)建了
可以理解為:
在函數(shù)上下文中:
VO === AO
在全局上下文中:
VO === this === global
總的來(lái)說(shuō)放典,VO中會(huì)存放一些變量信息(如聲明的變量逝变,函數(shù),arguments
參數(shù)等等)
作用域鏈
它是執(zhí)行上下文中的一個(gè)屬性奋构,原理和原型鏈很相似壳影,作用很重要。
譬如流程簡(jiǎn)述:
在函數(shù)上下文中弥臼,查找一個(gè)變量foo
如果函數(shù)的VO中找到了宴咧,就直接使用
否則去它的父級(jí)作用域鏈中(__parent__)找
如果父級(jí)中沒(méi)找到,繼續(xù)往上找
直到全局上下文中也沒(méi)找到就報(bào)錯(cuò)
this指針
這也是JS的核心知識(shí)之一径缅,由于內(nèi)容過(guò)多掺栅,這里就不展開(kāi),僅提及部分
注意:this是執(zhí)行上下文環(huán)境的一個(gè)屬性芥驳,而不是某個(gè)變量對(duì)象的屬性
因此:
this是沒(méi)有一個(gè)類似搜尋變量的過(guò)程
當(dāng)代碼中使用了this柿冲,這個(gè) this的值就直接從執(zhí)行的上下文中獲取了,而不會(huì)從作用域鏈中搜尋
this的值只取決中進(jìn)入上下文時(shí)的情況
所以經(jīng)典的例子:
var baz = 200;
var bar = {
baz: 100,
foo: function() {
console.log(this.baz);
}
};
var foo = bar.foo;
// 進(jìn)入環(huán)境:global
foo(); // 200兆旬,嚴(yán)格模式中會(huì)報(bào)錯(cuò),Cannot read property 'baz' of undefined
// 進(jìn)入環(huán)境:global bar
bar.foo(); // 100
就要明白了上面this的介紹怎栽,上述例子很好理解
更多參考:
深入理解JavaScript系列(13):This? Yes,this!
回收機(jī)制
JS有垃圾處理器丽猬,所以無(wú)需手動(dòng)回收內(nèi)存,而是由垃圾處理器自動(dòng)處理熏瞄。
一般來(lái)說(shuō)脚祟,垃圾處理器有自己的回收策略。
譬如對(duì)于那些執(zhí)行完畢的函數(shù)强饮,如果沒(méi)有外部引用(被引用的話會(huì)形成閉包)由桌,則會(huì)回收。(當(dāng)然一般會(huì)把回收動(dòng)作切割到不同的時(shí)間段執(zhí)行,防止影響性能)
常用的兩種垃圾回收規(guī)則是:
標(biāo)記清除
引用計(jì)數(shù)
Javascript引擎基礎(chǔ)GC方案是(simple GC
):mark and sweep
(標(biāo)記清除)行您,簡(jiǎn)單解釋如下:
遍歷所有可訪問(wèn)的對(duì)象铭乾。
回收已不可訪問(wèn)的對(duì)象。
譬如:(出自javascript高程)
當(dāng)變量進(jìn)入環(huán)境時(shí)娃循,例如炕檩,在函數(shù)中聲明一個(gè)變量,就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”捌斧。
從邏輯上講笛质,永遠(yuǎn)不能釋放進(jìn)入環(huán)境的變量所占用的內(nèi)存,因?yàn)橹灰獔?zhí)行流進(jìn)入相應(yīng)的環(huán)境捞蚂,就可能會(huì)用到它們妇押。
而當(dāng)變量離開(kāi)環(huán)境時(shí),則將其標(biāo)記為“離開(kāi)環(huán)境”姓迅。
垃圾回收器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記(當(dāng)然舆吮,可以使用任何標(biāo)記方式)。
然后队贱,它會(huì)去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記(閉包色冀,也就是說(shuō)在環(huán)境中的以及相關(guān)引用的變量會(huì)被去除標(biāo)記)。
而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量柱嫌,原因是環(huán)境中的變量已經(jīng)無(wú)法訪問(wèn)到這些變量了锋恬。
最后,垃圾回收器完成內(nèi)存清除工作编丘,銷毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間与学。
關(guān)于引用計(jì)數(shù),簡(jiǎn)單點(diǎn)理解:
跟蹤記錄每個(gè)值被引用的次數(shù)嘉抓,當(dāng)一個(gè)值被引用時(shí)索守,次數(shù)+1
,減持時(shí)-1
抑片,下次垃圾回收器會(huì)回收次數(shù)為0
的值的內(nèi)存(當(dāng)然了卵佛,容易出循環(huán)引用的bug)
GC的缺陷
和其他語(yǔ)言一樣,javascript的GC策略也無(wú)法避免一個(gè)問(wèn)題: GC時(shí)敞斋,停止響應(yīng)其他操作
這是為了安全考慮截汪。
而Javascript的GC在100ms
甚至以上
對(duì)一般的應(yīng)用還好,但對(duì)于JS游戲植捎,動(dòng)畫(huà)對(duì)連貫性要求比較高的應(yīng)用衙解,就麻煩了。
這就是引擎需要優(yōu)化的點(diǎn): 避免GC造成的長(zhǎng)時(shí)間停止響應(yīng)焰枢。
GC優(yōu)化策略
這里介紹常用到的:分代回收(Generation GC)
目的是通過(guò)區(qū)分“臨時(shí)”與“持久”對(duì)象:
多回收“臨時(shí)對(duì)象”區(qū)(
young generation
)少回收“持久對(duì)象”區(qū)(
tenured generation
)減少每次需遍歷的對(duì)象蚓峦,從而減少每次GC的耗時(shí)舌剂。
像node v8引擎就是采用的分代回收(和java一樣,作者是java虛擬機(jī)作者暑椰。)
更多可以參考:
其它
可以提到跨域
譬如發(fā)出網(wǎng)絡(luò)請(qǐng)求時(shí)霍转,會(huì)用AJAX,如果接口跨域干茉,就會(huì)遇到跨域問(wèn)題
可以參考:
可以提到web安全
譬如瀏覽器在解析HTML時(shí),有XSSAuditor
角虫,可以延伸到web安全相關(guān)領(lǐng)域
可以參考:
AJAX請(qǐng)求真的不安全么沾谓?談?wù)刉eb安全與AJAX的關(guān)系。
更多
如可以提到viewport
概念戳鹅,講講物理像素均驶,邏輯像素,CSS像素等概念
如熟悉Hybrid開(kāi)發(fā)的話可以提及一下Hybrid相關(guān)內(nèi)容以及優(yōu)化
…
總結(jié)
上述這么多內(nèi)容枫虏,目的是:梳理出自己的知識(shí)體系
本文由于是前端向妇穴,所以知識(shí)梳理時(shí)有重點(diǎn),很多其它的知識(shí)點(diǎn)都簡(jiǎn)述或略去了隶债,重點(diǎn)介紹的模塊總結(jié):
瀏覽器的進(jìn)程/線程模型腾它、JS運(yùn)行機(jī)制(這一塊的詳細(xì)介紹鏈接到了另一篇文章)
http規(guī)范(包括報(bào)文結(jié)構(gòu),頭部死讹,優(yōu)化瞒滴,http2.0,https等)
http緩存(單獨(dú)列出來(lái)赞警,因?yàn)樗苤匾?/p>
頁(yè)面解析流程(HTML解析妓忍,構(gòu)建DOM,生成CSS規(guī)則愧旦,構(gòu)建渲染樹(shù)世剖,渲染流程,復(fù)合層的合成笤虫,外鏈的處理等)
JS引擎解析過(guò)程(包括解釋階段旁瘫,預(yù)處理階段,執(zhí)行階段耕皮,包括執(zhí)行上下文境蜕、VO、作用域鏈凌停、this、回收機(jī)制等)
跨域相關(guān)售滤,web安全單獨(dú)鏈接到了具體文章罚拟,其它如CSS盒模型台诗,viewport等僅是提及概念
關(guān)于本文的價(jià)值?
本文是個(gè)人階段性梳理知識(shí)體系的成果赐俗,然后加以修繕后發(fā)布成文章拉队,因此并不確保適用于所有人員
但是,個(gè)人認(rèn)為本文還是有一定參考價(jià)值的
寫(xiě)在最后的話
還是那句話:知識(shí)要形成體系
梳理出知識(shí)體系后阻逮,有了一個(gè)骨架粱快,知識(shí)點(diǎn)不易遺忘,而且學(xué)習(xí)新知識(shí)時(shí)也會(huì)更加迅速叔扼,更重要的是容易舉一反三事哭,可以由一個(gè)普通的問(wèn)題,深挖拓展到底層原理
前端知識(shí)是無(wú)窮無(wú)盡的瓜富,本文也僅僅是簡(jiǎn)單梳理出一個(gè)承載知識(shí)體系的骨架而已鳍咱,更多的內(nèi)容仍然需要不斷學(xué)習(xí),積累
另外与柑,本文結(jié)合從瀏覽器多進(jìn)程到JS單線程谤辜,JS運(yùn)行機(jī)制最全面的一次梳理這篇文章,更佳噢价捧!