從輸入U(xiǎn)RL到頁(yè)面加載的過(guò)程嬉愧?如何由一道題完善自己的前端知識(shí)體系!

從輸入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ě)的是inheritgetComputedStyle也會(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定庵,scrollXXXclientXXXcurrentStyle等等

再舉一個(gè)例子:

  • visibility: hiddendisplay: 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)程)

如下圖:

image

多線程的瀏覽器內(nèi)核

每一個(gè)tab頁(yè)面可以看作是瀏覽器內(nèi)核進(jìn)程,然后這個(gè)進(jìn)程是多線程的贰军,它有幾大類子線程

  • GUI線程

  • JS引擎線程

  • 事件觸發(fā)線程

  • 定時(shí)器線程

  • 網(wǎng)絡(luò)請(qǐng)求線程

image

可以看到玻蝌,里面的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ì)把headersdata一起發(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)求

image

總之欲芹,當(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)要分析

image

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é)

image

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é)議

image

單獨(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.1http1.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-SinceLast-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-MatchE-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-ControlExpires她按,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-tagLast-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),顯示在屏幕上

如下圖:

image

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>

瀏覽器的處理如下:

image

列舉其中的一些重點(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ù)如下:

image

生成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ù)就是:

image

構(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ō)可以看圖:

image

渲染

有了render樹(shù),接下來(lái)就是開(kāi)始渲染蚪缀,基本流程如下:

image

圖中重要的四個(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à)推薦使用硬件加速

更多參考:

普通圖層和復(fù)合圖層

Chrome中的調(diào)試

Chrome的開(kāi)發(fā)者工具中尼荆,Performance中可以看到詳細(xì)的渲染過(guò)程:

image
image

資源外鏈的下載

上面介紹了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 屬性為absoluterelative或者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):

  1. 內(nèi)部box在垂直方向左医,一個(gè)接一個(gè)的放置

  2. box的垂直方向由margin決定,屬于同一個(gè)BFC的兩個(gè)box間的margin會(huì)重疊

  3. BFC區(qū)域不會(huì)與float box重疊(可用于排版)

  4. BFC就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器同木,容器里面的子元素不會(huì)影響到外面的元素浮梢。反之也如此

  5. 計(jì)算BFC的高度時(shí),浮動(dòng)元素也參與計(jì)算(不會(huì)浮動(dòng)坍塌)

如何觸發(fā)BFC彤路?

  1. 根元素

  2. float屬性不為none

  3. positionabsolutefixed

  4. displayinline-block, flex, inline-flex秕硝,tabletable-cell洲尊,table-caption

  5. 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)回收

image

然后執(zhí)行上下文與VO柳弄,作用域鏈,this的關(guān)系是:

每一個(gè)執(zhí)行上下文概说,都有三個(gè)重要屬性:

  • 變量對(duì)象(Variable object碧注,VO)

  • 作用域鏈(Scope chain)

  • this

image

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ò)

image

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)單解釋如下:

  1. 遍歷所有可訪問(wèn)的對(duì)象铭乾。

  2. 回收已不可訪問(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ī)作者暑椰。)

更多可以參考:

V8 內(nèi)存淺析

其它

可以提到跨域

譬如發(fā)出網(wǎng)絡(luò)請(qǐng)求時(shí)霍转,會(huì)用AJAX,如果接口跨域干茉,就會(huì)遇到跨域問(wèn)題

可以參考:

ajax跨域谴忧,這應(yīng)該是最全的解決方案了

可以提到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ī)制最全面的一次梳理這篇文章,更佳噢价捧!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末丑念,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子结蟋,更是在濱河造成了極大的恐慌脯倚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎眯,死亡現(xiàn)場(chǎng)離奇詭異挠将,居然都是意外死亡希柿,警方通過(guò)查閱死者的電腦和手機(jī)妇垢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)蔚润,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)硬爆,“玉大人曲楚,你說(shuō)我怎么就攤上這事欣簇⌒猓” “怎么了讨永?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵汞斧,是天一觀的道長(zhǎng)夜郁。 經(jīng)常有香客問(wèn)我,道長(zhǎng)粘勒,這世上最難降的妖魔是什么竞端? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮庙睡,結(jié)果婚禮上事富,老公的妹妹穿的比我還像新娘技俐。我一直安慰自己,他們只是感情好统台,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布雕擂。 她就那樣靜靜地躺著,像睡著了一般贱勃。 火紅的嫁衣襯著肌膚如雪井赌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天贵扰,我揣著相機(jī)與錄音仇穗,去河邊找鬼。 笑死拔鹰,一個(gè)胖子當(dāng)著我的面吹牛仪缸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播列肢,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼恰画,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了瓷马?” 一聲冷哼從身側(cè)響起拴还,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欧聘,沒(méi)想到半個(gè)月后片林,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怀骤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年费封,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒋伦。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弓摘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痕届,到底是詐尸還是另有隱情韧献,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布研叫,位于F島的核電站锤窑,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嚷炉。R本人自食惡果不足惜渊啰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望申屹。 院中可真熱鬧虽抄,春花似錦走搁、人聲如沸独柑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)忌栅。三九已至车酣,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間索绪,已是汗流浹背湖员。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瑞驱,地道東北人娘摔。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像唤反,于是被迫代替她去往敵國(guó)和親凳寺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

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