浏览器相关知识2
內(nèi)容整理來(lái)自極客時(shí)間李兵老師所講專(zhuān)欄《瀏覽器工作原理與實(shí)踐》
極客時(shí)間
-
棧空間和堆空間(js數(shù)據(jù)是如何存儲(chǔ)的)
- 在聲明變量之前需要先定義變量類(lèi)型,我們把這種在使用前就需要確認(rèn)變量數(shù)據(jù)類(lèi)型的稱為“靜態(tài)語(yǔ)音”;而相反地,我們把運(yùn)行過(guò)程中需要檢查數(shù)據(jù)類(lèi)型的語(yǔ)言稱為動(dòng)態(tài)語(yǔ)言(javascript就是個(gè)動(dòng)態(tài)語(yǔ)言)
- 支持隱式類(lèi)型轉(zhuǎn)換的語(yǔ)言被稱為“弱類(lèi)型語(yǔ)言”(javascript),而不支持隱式類(lèi)型轉(zhuǎn)換的語(yǔ)言稱為“強(qiáng)類(lèi)型語(yǔ)言”
- 在javascript的執(zhí)行過(guò)程中,主要有三種類(lèi)型內(nèi)存空間,分別是代碼空間,棧空間,堆空間function foo(){var a = "極客時(shí)間"var b = avar c = {name:"極客時(shí)間"}var d = c } foo()
- 為什么要設(shè)計(jì)出如此模式?
是因?yàn)閖avascript引擎需要用棧來(lái)維護(hù)程序執(zhí)行期間上下文的狀態(tài),如果棧空間大了話,所有的數(shù)據(jù)都存放在棧空間里面,那么會(huì)影響到上下文切換效率,進(jìn)而又影響到整個(gè)程序的執(zhí)行效率。
通常情況下,棧空間都不會(huì)設(shè)置太大,主要用來(lái)存放一些原始類(lèi)型的小數(shù)據(jù),而引用類(lèi)型占用空間比較大,堆空間很大,能存放很多大的數(shù)據(jù)。 - 閉包的數(shù)據(jù)其實(shí)是存在了堆當(dāng)中,而棧中存了個(gè)地址的引用。
-
垃圾回收:垃圾數(shù)據(jù)是如何自動(dòng)回收?
- 棧垃圾回收
當(dāng)函數(shù)執(zhí)行結(jié)束,JS引擎通過(guò)向下移動(dòng)”ESP”指針(記錄調(diào)用棧當(dāng)前執(zhí)行狀態(tài)的指針),來(lái)銷(xiāo)毀該函數(shù)保存在棧中的執(zhí)行上下文(變量環(huán)境,詞法環(huán)境,this,outer) - 堆垃圾回收
2.1 代際假說(shuō)
大部分對(duì)象存活時(shí)間都很短
不被銷(xiāo)毀的對(duì)象,會(huì)活的更久
2.2 分類(lèi)
V8引擎會(huì)把堆分為新生代和老生代兩個(gè)區(qū)域,新生代中存放的是生存時(shí)間短的對(duì)象,老生代中存放的生存時(shí)間久的對(duì)象
2.3 新生代
算法:Scavenge算法
原理:
2.3.1 把新生代空間對(duì)半劃分為兩個(gè)區(qū)域,一半是對(duì)象區(qū)域,一半是空閑區(qū)域
2.3.2 新加入的對(duì)象都會(huì)存放到對(duì)象區(qū)域,當(dāng)對(duì)象區(qū)域快被寫(xiě)滿時(shí),就需要執(zhí)行一次垃圾清理操作
2.3.3 先對(duì)對(duì)象區(qū)域中的垃圾做標(biāo)記,標(biāo)記完成之后,把這些存活的對(duì)象復(fù)制到空閑區(qū)域中
2.3.4 完成復(fù)制后,對(duì)象區(qū)域與空閑區(qū)域進(jìn)行角色翻轉(zhuǎn),也激素hi原來(lái)的對(duì)象區(qū)域變成空閑區(qū)域,原來(lái)的空閑區(qū)域變成了對(duì)象區(qū)域
2.3.5 經(jīng)過(guò)兩次垃圾回收依然還存活的對(duì)象,會(huì)被移動(dòng)到老生區(qū)中
2.4 老生代
算法:標(biāo)記-清除(Mark-Sweep)算法
原理:
2.4.1 標(biāo)記:標(biāo)記階段就是從一組根元素開(kāi)始,遞歸遍歷這組根元素,在這個(gè)遍歷過(guò)程中,能到達(dá)的元素稱為活動(dòng)對(duì)象,沒(méi)有到達(dá)的元素就可以判斷為垃圾數(shù)據(jù)。
2.4.2 清除:將垃圾數(shù)據(jù)進(jìn)行清除
2.4.3 碎片:對(duì)一塊內(nèi)存多次執(zhí)行標(biāo)記-清除算法后,會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,而碎片過(guò)多會(huì)導(dǎo)致大對(duì)象無(wú)法分配到足夠的連續(xù)內(nèi)存
2.4.4 算法:標(biāo)記-整理(Mark-Compact)算法
2.4.4.1 標(biāo)記: 和標(biāo)記-清除的標(biāo)記過(guò)程一樣,從一組根元素開(kāi)始,遞歸遍歷這組根元素,這個(gè)遍歷過(guò)程中,能到達(dá)的元素標(biāo)記為活動(dòng)對(duì)象
2.4.4.2 整理:讓所有存活的對(duì)象都向內(nèi)存的一端移動(dòng)
2.4.4.3 清除:清理掉端邊界以外的內(nèi)存
2.4.5 優(yōu)化算法:增量-標(biāo)記(Incaremental Marking)算法
2.4.5.1 為了降低老生代的垃圾回收而造成的卡頓
2.4.5.2 V8把一個(gè)完整的垃圾回收任務(wù)拆分為很多小的任務(wù)
2.4.5.3 讓垃圾回收標(biāo)記和js應(yīng)用邏輯交替執(zhí)行 -
編譯器和解釋器:v8是如何執(zhí)行一段js代碼的?
-
V8如何執(zhí)行一段js代碼?
1.1 生成抽象語(yǔ)法樹(shù)(AST)和可執(zhí)行上下文1.1.1 AST(抽象語(yǔ)法樹(shù))
生成AST需要經(jīng)過(guò)兩個(gè)階段:
第一個(gè)階段是“分詞”(tokenize),又稱為詞法分析:其作用是將一行行的源碼拆解成一個(gè)個(gè)token,token指的是在語(yǔ)法上不可能再分的,最小的單個(gè)字符或者字符串。
第二個(gè)階段是“解析”(parse),又稱為語(yǔ)法分析:其作用是將上一步生成的token數(shù)據(jù),根據(jù)語(yǔ)法規(guī)則轉(zhuǎn)換為AST,如果源碼符合語(yǔ)法規(guī)則,這一步就會(huì)順利完成,但如果源碼存在語(yǔ)法錯(cuò)誤,這一步就會(huì)終止,并拋出一個(gè)“語(yǔ)法錯(cuò)誤”。
1.1.2 生成可執(zhí)行上下文(變量環(huán)境,詞法環(huán)境,外部環(huán)境,this)1.2 生成字節(jié)碼
解釋器lgnition,它會(huì)根據(jù)AST生成字節(jié)碼,并解釋執(zhí)行字節(jié)碼,字節(jié)碼就是介于AST和機(jī)器碼之間的一種代碼,但是與特定類(lèi)型的機(jī)器碼無(wú)關(guān),字節(jié)碼需要通過(guò)解釋器將其轉(zhuǎn)換為機(jī)器碼后才能執(zhí)行。
同時(shí)Ignition也兼任了“生成字節(jié)碼”和“解釋字節(jié)碼”兩個(gè)作用,當(dāng)Ignition執(zhí)行字節(jié)碼的過(guò)程中,如果發(fā)現(xiàn)有熱點(diǎn)代碼(比如同一段代碼執(zhí)行了多次),這個(gè)時(shí)候另一個(gè)編譯器TurboFan就會(huì)把該熱點(diǎn)的字節(jié)碼編譯為高效的機(jī)器碼。這種模式字節(jié)碼配合解釋器和編譯器稱為“即時(shí)編譯”(JIT)
-
JavaScript的性能優(yōu)化
2.1 提升單次腳本的執(zhí)行速度,避免js的長(zhǎng)任務(wù)霸占主線程,這樣可以使得頁(yè)面快速響應(yīng)交互
2.2 避免大的內(nèi)聯(lián)腳本,因?yàn)樵诮馕鯤TML的過(guò)程中,解析和編譯也會(huì)占用主線程
2.3 減少JavaScript文件的容量,因?yàn)楦〉奈募?huì)提升下載速度,并且占用更低的內(nèi)存 -
消息隊(duì)列和事件循環(huán):頁(yè)面是怎么“活”起來(lái)的?
- 為什么需要消息隊(duì)列和事件循環(huán)?
在每一個(gè)渲染進(jìn)程都會(huì)有一個(gè)主線程,并且主線程非常繁忙,既要處理DOM,又要計(jì)算樣式,還要處理布局,同時(shí)還需要處理JavaScript任務(wù)以及各種輸入事件,要讓這么多不同類(lèi)型的任務(wù)在主線程中有條不紊地執(zhí)行,所以需要該兩者。 - 事件循環(huán)
想要在線程運(yùn)行過(guò)程中,能接收并執(zhí)行新的任務(wù),就需要采用事件循環(huán)機(jī)制,這樣就會(huì)一直來(lái)接收新的任務(wù)。
- 渲染進(jìn)程中其他線程是如何發(fā)送消息給渲染主線程?
渲染主線程會(huì)頻繁的接收來(lái)自于IO線程的一些任務(wù),接收后,渲染線程就需要著手處理。比如:接收到資源加載完,需要進(jìn)行DOM解析;比如:接收到鼠標(biāo)點(diǎn)擊后,需要進(jìn)行javascript腳本來(lái)處理該點(diǎn)擊事件。
- 消息隊(duì)列
消息隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),可以存放要執(zhí)行的任務(wù)。它符合隊(duì)列“先進(jìn)先出”的特點(diǎn),也就是說(shuō)要添加任務(wù)的話,添加到隊(duì)列的尾部;要取出任務(wù)的話,從隊(duì)列頭部去取。
- 如何處理其他進(jìn)程發(fā)來(lái)的消息?
渲染進(jìn)程專(zhuān)門(mén)有一個(gè)IO線程用來(lái)接收其他進(jìn)程傳進(jìn)來(lái)的消息(通過(guò)進(jìn)程間的傳輸IPC,比如網(wǎng)絡(luò)進(jìn)程標(biāo)識(shí)資源加載完成,比如瀏覽器進(jìn)程表示鼠標(biāo)點(diǎn)擊),接收到消息后,會(huì)將這些消息組裝成任務(wù)發(fā)送給渲染主線程,后續(xù)的步驟跟前面圖一樣處理邏輯。
- 頁(yè)面使用單線程的缺點(diǎn)
頁(yè)面線程中的所有執(zhí)行的任務(wù)都來(lái)自于消息隊(duì)列,消息隊(duì)列是“先進(jìn)先出”的屬性,也就是說(shuō)放入隊(duì)列中的任務(wù),需要等待前面的任務(wù)被執(zhí)行完,才會(huì)被執(zhí)行。
6.1 如何處理高優(yōu)先級(jí)的任務(wù)
一個(gè)通用的設(shè)計(jì)是,利用javascript設(shè)計(jì)一套監(jiān)聽(tīng)接口,當(dāng)變化發(fā)生時(shí),渲染引擎同步調(diào)用這些接口,這是一個(gè)典型的觀察者模式。當(dāng)DOM變化非常頻繁,那么當(dāng)前這個(gè)任務(wù)執(zhí)行時(shí)間就會(huì)被拉長(zhǎng),從而導(dǎo)致“執(zhí)行效率下降”。如果將DOM變化做成異步消息事件,添加到消息隊(duì)列的尾部,那么又會(huì)影響到監(jiān)控的實(shí)時(shí)性,因?yàn)樘砑拥较㈥?duì)列的過(guò)程中,前面就有很多任務(wù)在排隊(duì)了。
這也就是說(shuō),如果DOM發(fā)生變化,采用同步通知的方式,會(huì)影響當(dāng)前任務(wù)的執(zhí)行效率,如果采用異步方式,又會(huì)影響到監(jiān)控的實(shí)時(shí)性。因此“微任務(wù)”應(yīng)用而生了。
通常我們把消息隊(duì)列中的任務(wù)稱為“宏任務(wù)”,每個(gè)宏任務(wù)中都包含了一個(gè)“微任務(wù)隊(duì)列”
等當(dāng)前宏任務(wù)的主要功能都直接完成之后,這個(gè)時(shí)候,渲染引擎并不會(huì)立即執(zhí)行下一個(gè)宏任務(wù),而是執(zhí)行當(dāng)前宏任務(wù)中的微任務(wù),然后再執(zhí)行下一個(gè)宏任務(wù)。
6.2 如何解決單個(gè)任務(wù)執(zhí)行時(shí)長(zhǎng)過(guò)久的問(wèn)題
針對(duì)該情況,javascript可以使用回調(diào)功能來(lái)規(guī)避這種問(wèn)題,也就是讓要執(zhí)行的javascript任務(wù)滯后執(zhí)行。 -
WebAPI:setTimeout如何實(shí)現(xiàn)的?
瀏覽器的頁(yè)面是通過(guò)消息隊(duì)列和事件循環(huán)系統(tǒng)來(lái)驅(qū)動(dòng)的。settimeout的函數(shù)會(huì)被加入到延遲消息隊(duì)列中,等到執(zhí)行完Task任務(wù)之后就會(huì)執(zhí)行延遲隊(duì)列中的任務(wù)。然后分析幾種場(chǎng)景下面的setimeout的執(zhí)行方式。
- 如果執(zhí)行一個(gè)很耗時(shí)的任務(wù),會(huì)影響延遲消息隊(duì)列中任務(wù)的執(zhí)行
- 存在嵌套帶調(diào)用時(shí)候,系統(tǒng)會(huì)設(shè)置最短時(shí)間間隔為4s(超過(guò)5層)
- 未激活的頁(yè)面,setTimeout最小時(shí)間間隔為1000ms
- 延時(shí)執(zhí)行時(shí)間的最大值2147483647,溢出會(huì)導(dǎo)致定時(shí)器立即執(zhí)行
- setTimeout設(shè)置回調(diào)函數(shù)this會(huì)是回調(diào)時(shí)候?qū)?yīng)的this對(duì)象,可以使用箭頭函數(shù)解決
-
WebAPI: xmlHttpRequest是怎么實(shí)現(xiàn)的?
從上面來(lái)看原始類(lèi)型的數(shù)值都是直接保存在“棧”中的,引用類(lèi)型是存放在“堆”中。
-
async和await
-
生成器
生成器函數(shù)是一個(gè)帶星號(hào)函數(shù),而且是可以暫停執(zhí)行和恢復(fù)執(zhí)行的;
在生成器函數(shù)內(nèi)部執(zhí)行一段代碼,如果遇到 yield 關(guān)鍵字,那么 JavaScript 引擎將返回關(guān)鍵字后面的內(nèi)容給外部,并暫停該函數(shù)的執(zhí)行;
外部函數(shù)可以通過(guò) next 方法恢復(fù)函數(shù)的執(zhí)行。 -
協(xié)程
2.1 為什么函數(shù)能暫停和恢復(fù),這全部得歸功于“協(xié)程“。協(xié)程是一種比線程更加輕量級(jí)的存在。可以把協(xié)程看成是跑在線程上的任務(wù),一個(gè)線程上可以存在多個(gè)協(xié)程,但是在線程上同時(shí)只能執(zhí)行一個(gè)協(xié)程。
2.2 比如當(dāng)前執(zhí)行的是A協(xié)程,要啟動(dòng)B協(xié)程,那么A協(xié)程就需要將主線程的控制權(quán)交給B協(xié)程,這就體現(xiàn)在A協(xié)程暫停執(zhí)行,B協(xié)程恢復(fù)執(zhí)行;同樣,也可以從B協(xié)程中啟動(dòng)A協(xié)程。通常,如果從A協(xié)程啟動(dòng)B協(xié)程,我們就把A協(xié)程稱為B協(xié)程的父協(xié)程。
-
Async
async function foo() {return 2 } console.log(foo()) // Promise {<resolved>: 2} 這里執(zhí)行函數(shù)后 居然返回的是一個(gè)Promise對(duì)象,狀態(tài)是reolved
Async是一個(gè)通過(guò)異步執(zhí)行并隱式返回Promise作為結(jié)果的函數(shù)。 -
Await
比如:await 100 那么就會(huì)創(chuàng)建 new Promise(resolve,reject => {resolve(100) })
當(dāng)執(zhí)行await的時(shí)候,會(huì)默認(rèn)創(chuàng)建一個(gè)Promise對(duì)象。 -
Async/await
本質(zhì)上這個(gè)語(yǔ)法糖的基礎(chǔ)技術(shù)使用了生成器和Promise結(jié)合,生成器是協(xié)程的實(shí)現(xiàn),利用生成器能實(shí)現(xiàn)生成函數(shù)的暫停和恢復(fù)。 -
chrome開(kāi)發(fā)者工具:利用網(wǎng)絡(luò)面板做性能分析
-
工具介紹
-
NetWork(網(wǎng)絡(luò)面板)
2.1 控制器
2.1.1 紅色圓點(diǎn)的按鈕,表示“開(kāi)始 / 暫停抓包”,這個(gè)功能很常見(jiàn),很容易理解。
2.1.2 “全局搜索”按鈕,這個(gè)功能就非常重要了,可以在所有下載資源中搜索相關(guān)內(nèi)容,還可以快速定位到某幾個(gè)你想要的文件上。
2.1.3 Disable cache,即“禁止從 Cache 中加載資源”的功能,它在調(diào)試 Web 應(yīng)用的時(shí)候非常有用,因?yàn)殚_(kāi)啟了 Cache 會(huì)影響到網(wǎng)絡(luò)性能測(cè)試的結(jié)果。
2.1.4 Online 按鈕,是“模擬 2G/3G”功能,它可以限制帶寬,模擬弱網(wǎng)情況下頁(yè)面的展現(xiàn)情況,然后你就可以根據(jù)實(shí)際展示情況來(lái)動(dòng)態(tài)調(diào)整策略,以便讓 Web 應(yīng)用更加適用于這些弱網(wǎng)。2.2 過(guò)濾器
網(wǎng)絡(luò)面板中的過(guò)濾器,主要就是起過(guò)濾功能。因?yàn)橛袝r(shí)候一個(gè)頁(yè)面有太多內(nèi)容在詳細(xì)列表區(qū)域中展示了,而你可能只想查看 JavaScript 文件或者 CSS 文件,這時(shí)候就可以通過(guò)過(guò)濾器模塊來(lái)篩選你想要的文件類(lèi)型。
2.3 抓圖信息
抓圖信息區(qū)域,可以用來(lái)分析用戶等待頁(yè)面加載時(shí)間內(nèi)所看到的內(nèi)容,分析用戶實(shí)際的體驗(yàn)情況。比如,如果頁(yè)面加載 1 秒多之后屏幕截圖還是白屏狀態(tài),這時(shí)候就需要分析是網(wǎng)絡(luò)還是代碼的問(wèn)題了。(勾選面板上的“Capture screenshots”即可啟用屏幕截圖。)
2.4 時(shí)間線
時(shí)間線,主要用來(lái)展示 HTTP、HTTPS、WebSocket 加載的狀態(tài)和時(shí)間的一個(gè)關(guān)系,用于直觀感受頁(yè)面的加載過(guò)程。如果是多條豎線堆疊在一起,那說(shuō)明這些資源被同時(shí)被加載。至于具體到每個(gè)文件的加載信息,還需要用到下面要講的詳細(xì)列表。
2.5 詳細(xì)列表
這個(gè)區(qū)域是最重要的,它詳細(xì)記錄了每個(gè)資源從發(fā)起請(qǐng)求到完成請(qǐng)求這中間所有過(guò)程的狀態(tài),以及最終請(qǐng)求完成的數(shù)據(jù)信息。通過(guò)該列表,你就能很容易地去診斷一些網(wǎng)絡(luò)問(wèn)題。
2.6 下載信息概要
DOMContentLoaded,這個(gè)事件發(fā)生后,說(shuō)明頁(yè)面已經(jīng)構(gòu)建好 DOM 了,這意味著構(gòu)建 DOM 所需要的 HTML 文件、JavaScript 文件、CSS 文件都已經(jīng)下載完成了。
Load,說(shuō)明瀏覽器已經(jīng)加載了所有的資源(圖像、樣式表等)。 -
單個(gè)資源的時(shí)間線
3.1 發(fā)起http請(qǐng)求
3.2 瀏覽器查找緩存(若緩存沒(méi)命中)
3.3 發(fā)起DNS請(qǐng)求獲取IP地址
3.4 利用IP地址和服務(wù)器建立TCP連接
3.5 等待服務(wù)器響應(yīng)
3.6 若服務(wù)器響應(yīng)頭包含了重定向信息,則整個(gè)流程重新走一遍。
3.7 Queueing(排隊(duì))-》Resource Scheduling階段
當(dāng)瀏覽器發(fā)起一個(gè)請(qǐng)求,會(huì)有很多原因?qū)е略撜?qǐng)求不能被立即執(zhí)行,而是需要排隊(duì)等待,排隊(duì)的原因有很多:
3.7.1 頁(yè)面中的資源是有優(yōu)先級(jí)的,比如 CSS、HTML、JavaScript 等都是頁(yè)面中的核心文件,所以優(yōu)先級(jí)最高;而圖片、視頻、音頻這類(lèi)資源就不是核心資源,優(yōu)先級(jí)就比較低。通常當(dāng)后者遇到前者時(shí),就需要“讓路”,進(jìn)入待排隊(duì)狀態(tài)。
3.7.2 瀏覽器會(huì)為每個(gè)域名最多維護(hù) 6 個(gè) TCP 連接,如果發(fā)起一個(gè) HTTP 請(qǐng)求時(shí),這 6 個(gè) TCP 連接都處于忙碌狀態(tài),那么這個(gè)請(qǐng)求就會(huì)處于排隊(duì)狀態(tài)。
3.7.3 網(wǎng)絡(luò)進(jìn)程在為數(shù)據(jù)分配磁盤(pán)空間時(shí),新的 HTTP 請(qǐng)求也需要短暫地等待磁盤(pán)分配結(jié)束。
3.8 Stalled(停滯)-》Connection Start階段
排隊(duì)完成后,就要進(jìn)入發(fā)起連接狀態(tài),不過(guò)在發(fā)起連接之前,還有一些原因?qū)е逻B接過(guò)程被推遲
3.9 Proxy Negotiation(代理協(xié)商階段)-》Connection Start階段
表示代理服務(wù)器連接協(xié)商所用的時(shí)間
3.10 DNS Lookup (dns查詢)-》Connection Start階段
Dns查詢所用的時(shí)間
3.11 Initial connection/SSL 階段 -》Connection Start階段
也就是和服務(wù)器建立連接的階段,這包括了建立 TCP 連接所花費(fèi)的時(shí)間;不過(guò)如果你使用了 HTTPS 協(xié)議,那么還需要一個(gè)額外的 SSL 握手時(shí)間,這個(gè)過(guò)程主要是用來(lái)協(xié)商一些加密信息的
3.12 Request Sent
網(wǎng)絡(luò)進(jìn)程會(huì)準(zhǔn)備請(qǐng)求數(shù)據(jù),并將其發(fā)送給網(wǎng)絡(luò), 只需要把瀏覽器緩沖區(qū)的數(shù)據(jù)發(fā)送出去就結(jié)束了,并不需要判斷服務(wù)器是否接收到了
3.13 Waiting(TTFB)
接下來(lái)就是等待接收服務(wù)器第一個(gè)字節(jié)的數(shù)據(jù),TTFB 是反映服務(wù)端響應(yīng)速度的重要指標(biāo),對(duì)服務(wù)器來(lái)說(shuō),TTFB 時(shí)間越短,就說(shuō)明服務(wù)器響應(yīng)越快。
3.14 Content Download
接收到第一個(gè)字節(jié)之后,進(jìn)入陸續(xù)接收完整數(shù)據(jù)的階段, 這意味著從第一字節(jié)時(shí)間到接收到全部響應(yīng)數(shù)據(jù)所用的時(shí)間。 -
優(yōu)化線上耗時(shí)項(xiàng)
4.1 排隊(duì)(Queuing)時(shí)間過(guò)久
4.1.1 大概率是由瀏覽器為每個(gè)域名最多維護(hù)6個(gè)連接導(dǎo)致的(參考域名分片技術(shù))
4.1.2 把站點(diǎn)升級(jí)到HTTP2(無(wú)6個(gè)連接限制)
4.2 第一字節(jié)(TTFB)時(shí)間過(guò)久
4.2.1 服務(wù)器生成頁(yè)面數(shù)據(jù)的時(shí)間過(guò)久
4.2.2 網(wǎng)絡(luò)原因
4.2.3 發(fā)送請(qǐng)求頭時(shí)帶上了多余的用戶信息
4.3 content download 時(shí)間過(guò)久
4.3.1 單個(gè)請(qǐng)求content download過(guò)久,有可能是字節(jié)數(shù)太多,這個(gè)時(shí)候減少文件大小,比如壓縮,去掉源碼中不必要的注釋。 -
js是如何影響DOM樹(shù)創(chuàng)建的
- 首先介紹了什么是DOM(表述渲染引擎內(nèi)部數(shù)據(jù)結(jié)構(gòu),它將Web頁(yè)面和JavaScript腳本連接起來(lái),并過(guò)濾不安全內(nèi)容)、DOM樹(shù)如何生成(網(wǎng)絡(luò)進(jìn)程和渲染進(jìn)程建立一個(gè)流式管道,HTML解析器直接解析,不需要等待text/html類(lèi)型的接口 接受完畢再進(jìn)行解析),第一步:通過(guò)分詞器將字節(jié)流轉(zhuǎn)換為T(mén)oken;第二步:將Token解析為DOM節(jié)點(diǎn);第三步:將DOM節(jié)點(diǎn)添加到DOM樹(shù)中。
- JavaScript是如何影響DOM生成的?暫停html解析,下載解析執(zhí)行完畢js之后再進(jìn)行html解析(如果這期間使用到了cssDom,需要等待相應(yīng)css過(guò)程)。預(yù)解析線程的優(yōu)化(提前加載相應(yīng)js css文件)
- 渲染引擎還有一個(gè)安全檢查模塊XSSAuditor用來(lái)檢測(cè)詞法安全的。
- Async和defer區(qū)別及用途
4.1 async: 腳本并行加載,加載完成之后立即執(zhí)行,執(zhí)行時(shí)機(jī)不確定,仍有可能阻塞HTML解析,執(zhí)行時(shí)機(jī)在load事件派發(fā)之前。
4.1.1 只適用于外聯(lián)腳本
4.1.2 如果有多個(gè)聲明了async的腳本,其下載和執(zhí)行也是異步的,不能確保彼此的先后順序
4.1.3 async會(huì)在load事件之前執(zhí)行,但并不能確保與DOMContentLoaded的執(zhí)行先后順序
4.2 defer: 腳本并行加載,等待HTML解析完成之后,按照加載順序執(zhí)行腳本,執(zhí)行時(shí)機(jī)在DOMContentLoaded事件派發(fā)之前。
4.2.1 defer只適用于外聯(lián)腳本,如果script標(biāo)簽沒(méi)有指定src屬性,只是內(nèi)聯(lián)腳本,不要使用defer,非常它會(huì)同步執(zhí)行
4.2.2 如果有多個(gè)聲明了defer的腳本,則會(huì)按順序下載和執(zhí)行
4.2.3 defer腳本會(huì)在DOMContentLoaded和load事件之前執(zhí)行
總結(jié)
- 上一篇: 8.找出链表环的入口结点
- 下一篇: JAVA java学习(46)—————