欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    瀏覽器背后的運(yùn)行機(jī)制

    從本章開始,我們的性能優(yōu)化探險(xiǎn)也正式進(jìn)入到了“深水區(qū)”——瀏覽器端的性能優(yōu)化。

    平時(shí)我們幾乎每天都在和瀏覽器打交道,在一些兼容任務(wù)比較繁重的團(tuán)隊(duì)里,苦逼的前端攻城師們甚至為了兼容各個(gè)瀏覽器而不斷地去測(cè)試和調(diào)試,還要在腦子中記下各種遇到的 BUG 及解決方案。即便如此瀏覽器工作原理是怎樣的,我們好像并沒有去主動(dòng)地關(guān)注和了解下瀏覽器的工作原理。我想如果我們對(duì)此做一點(diǎn)了解,在項(xiàng)目過程中就可以有效地避免一些問題,并對(duì)頁(yè)面性能做出相應(yīng)的改進(jìn)。

    “知己知彼,百戰(zhàn)不殆”,今天,我們就一起來揭開瀏覽器渲染過程的神秘面紗!

    瀏覽器的“心”

    瀏覽器的“心”,說的就是瀏覽器的內(nèi)核。在研究瀏覽器微觀的運(yùn)行機(jī)制之前,我們首先要對(duì)瀏覽器內(nèi)核有一個(gè)宏觀的把握。

    開篇我提到許多工程師因?yàn)闃I(yè)務(wù)需要,免不了需要去處理不同瀏覽器下代碼渲染結(jié)果的差異性。這些差異性正是因?yàn)闉g覽器內(nèi)核的不同而導(dǎo)致的——瀏覽器內(nèi)核決定了瀏覽器解釋網(wǎng)頁(yè)語法的方式。

    瀏覽器內(nèi)核可以分成兩部分:渲染引擎( 或者 )和 JS 引擎。早期渲染引擎和 JS 引擎并沒有十分明確的區(qū)分,但隨著 JS 引擎越來越獨(dú)立,內(nèi)核也成了渲染引擎的代稱(下文我們將沿用這種叫法)。渲染引擎又包括了 HTML 解釋器、CSS 解釋器、布局、網(wǎng)絡(luò)、存儲(chǔ)、圖形、音視頻、圖片解碼器等等零部件。

    目前市面上常見的瀏覽器內(nèi)核可以分為這四種:(IE)、Gecko(火狐)、Blink(、Opera)、()。

    這里面大家最耳熟能詳?shù)目赡芫褪? 內(nèi)核了。很多同學(xué)可能會(huì)聽說過 的內(nèi)核就是 ,殊不知 內(nèi)核早已迭代為了 Blink。但是換湯不換藥,Blink 其實(shí)也是基于 衍生而來的一個(gè)分支,因此, 內(nèi)核仍然是當(dāng)下瀏覽器世界真正的霸主。

    下面我們就以 為例,對(duì)現(xiàn)代瀏覽器的渲染過程進(jìn)行一個(gè)深度的剖析。

    開啟瀏覽器渲染“黑盒”

    什么是渲染過程?簡(jiǎn)單來說,渲染引擎根據(jù) HTML 文件描述構(gòu)建相應(yīng)的數(shù)學(xué)模型,調(diào)用瀏覽器各個(gè)零部件,從而將網(wǎng)頁(yè)資源代碼轉(zhuǎn)換為圖像結(jié)果,這個(gè)過程就是渲染過程(如下圖)。

    從這個(gè)流程來看,瀏覽器呈現(xiàn)網(wǎng)頁(yè)這個(gè)過程,宛如一個(gè)黑盒。在這個(gè)神秘的黑盒中,有許多功能模塊,內(nèi)核內(nèi)部的實(shí)現(xiàn)正是這些功能模塊相互配合協(xié)同工作進(jìn)行的。其中我們最需要關(guān)注的,就是HTML 解釋器、CSS 解釋器、圖層布局計(jì)算模塊、視圖繪制模塊與 引擎這幾大模塊:

    瀏覽器渲染過程解析

    有了對(duì)零部件的了解打底,我們就可以一起來走一遍瀏覽器的渲染流程了。在瀏覽器里,每一個(gè)頁(yè)面的首次渲染都經(jīng)歷了如下階段(圖中箭頭不代表串行,有一些操作是并行進(jìn)行的,下文會(huì)說明):

    幾棵重要的“樹”

    上面的內(nèi)容沒有理解透徹?別著急,我們一起來捋一捋這個(gè)過程中的重點(diǎn)——樹!

    文獻(xiàn)檢索與應(yīng)用瀏覽是_工作說明書是工作分析的_瀏覽器工作原理是怎樣的

    為了使渲染過程更明晰一些,我們需要給這些”樹“們一個(gè)特寫:

    基于這些“樹”,我們?cè)偈崂硪环?/p>

    渲染過程說白了,首先是基于 HTML 構(gòu)建一個(gè) DOM 樹,這棵 DOM 樹與 CSS 解釋器解析出的 CSSOM 相結(jié)合,就有了布局渲染樹。最后瀏覽器以布局渲染樹為藍(lán)本,去計(jì)算布局并繪制圖像,我們頁(yè)面的初次渲染就大功告成了。

    之后每當(dāng)一個(gè)新元素加入到這個(gè) DOM 樹當(dāng)中,瀏覽器便會(huì)通過 CSS 引擎查遍 CSS 樣式表,找到符合該元素的樣式規(guī)則應(yīng)用到這個(gè)元素上,然后再重新去繪制它。

    有心的同學(xué)可能已經(jīng)在思考了,查表是個(gè)花時(shí)間的活,我怎么讓瀏覽器的查詢工作又快又好地實(shí)現(xiàn)呢?OK,講了這么多原理,我們終于引出了我們的第一個(gè)可轉(zhuǎn)化為代碼的優(yōu)化點(diǎn)——CSS 樣式表規(guī)則的優(yōu)化!

    不做無用功:基于渲染流程的 CSS 優(yōu)化建議

    在給出 CSS 選擇器方面的優(yōu)化建議之前,先告訴大家一個(gè)小知識(shí):CSS 引擎查找樣式表,對(duì)每條規(guī)則都按從右到左的順序去匹配。 看如下規(guī)則:

    css">#myList  li {}
    

    這樣的寫法其實(shí)很常見。大家平時(shí)習(xí)慣了從左到右閱讀的文字閱讀方式,會(huì)本能地以為瀏覽器也是從左到右匹配 CSS 選擇器的,因此會(huì)推測(cè)這個(gè)選擇器并不會(huì)費(fèi)多少力氣:# 是一個(gè) id 選擇器,它對(duì)應(yīng)的元素只有一個(gè),查找起來應(yīng)該很快。定位到了 元素,等于是縮小了范圍后再去查找它后代中的 li 元素,沒毛病。

    事實(shí)上,CSS 選擇符是從右到左進(jìn)行匹配的。我們這個(gè)看似“沒毛病”的選擇器,實(shí)際開銷相當(dāng)高:瀏覽器必須遍歷頁(yè)面上每個(gè) li 元素,并且每次都要去確認(rèn)這個(gè) li 元素的父元素 id 是不是 ,你說坑不坑!

    說到坑,不知道大家還記不記得這個(gè)經(jīng)典的通配符:

    * {}
    

    入門 CSS 的時(shí)候,不少同學(xué)拿通配符清除默認(rèn)樣式(我曾經(jīng)也是通配符用戶的一員)。但這個(gè)家伙很恐怖,它會(huì)匹配所有元素,所以瀏覽器必須去遍歷每一個(gè)元素!大家低頭看看自己頁(yè)面里的元素個(gè)數(shù),是不是心涼了——這得計(jì)算多少次呀!

    這樣一看,一個(gè)小小的 CSS 選擇器,也有不少的門道!好的 CSS 選擇器書寫習(xí)慣,可以為我們帶來非??捎^的性能提升。根據(jù)上面的分析,我們至少可以總結(jié)出如下性能提升的方案:

    false:

    #myList li{}
    

    true:

    瀏覽器工作原理是怎樣的_工作說明書是工作分析的_文獻(xiàn)檢索與應(yīng)用瀏覽是

    .myList_li {}
    

    false:

    .myList#title
    

    true:

    #title
    

    搞定了 CSS 選擇器,萬里長(zhǎng)征才剛剛開始的第一步。但現(xiàn)在你已經(jīng)理解了瀏覽器的工作過程,接下來的征程對(duì)你來說并不再是什么難題~

    告別阻塞:CSS 與 JS 的加載順序優(yōu)化

    說完了過程,我們來說一說特性。

    HTML、CSS 和 JS,都具有阻塞渲染的特性。

    HTML 阻塞,天經(jīng)地義——沒有 HTML,何來 DOM?沒有 DOM,渲染和優(yōu)化,都是空談。

    那么 CSS 和 JS 的阻塞又是怎么回事呢?

    CSS 的阻塞

    在剛剛的過程中,我們提到 DOM 和 CSSOM 合力才能構(gòu)建渲染樹。這一點(diǎn)會(huì)給性能造成嚴(yán)重影響:默認(rèn)情況下,CSS 是阻塞的資源。瀏覽器在構(gòu)建 CSSOM 的過程中,不會(huì)渲染任何已處理的內(nèi)容。即便 DOM 已經(jīng)解析完畢了,只要 CSSOM 不 OK,那么渲染這個(gè)事情就不 OK(這主要是為了避免沒有 CSS 的 HTML 頁(yè)面丑陋地“裸奔”在用戶眼前)。

    我們知道,只有當(dāng)我們開始解析 HTML 后、解析到 link 標(biāo)簽或者 style 標(biāo)簽時(shí),CSS 才登場(chǎng),CSSOM 的構(gòu)建才開始。很多時(shí)候,DOM 不得不等待 CSSOM。因此我們可以這樣總結(jié):

    CSS 是阻塞渲染的資源。需要將它盡早、盡快地下載到客戶端,以便縮短首次渲染的時(shí)間。

    事實(shí)上,現(xiàn)在很多團(tuán)隊(duì)都已經(jīng)做到了盡早(將 CSS 放在 head 標(biāo)簽里)和盡快(啟用 CDN 實(shí)現(xiàn)靜態(tài)資源加載速度的優(yōu)化)。這個(gè)“把 CSS 往前放”的動(dòng)作,對(duì)很多同學(xué)來說已經(jīng)內(nèi)化為一種編碼習(xí)慣。那么現(xiàn)在我們還應(yīng)該知道,這個(gè)“習(xí)慣”不是空穴來風(fēng),它是由 CSS 的特性決定的。

    JS 的阻塞

    不知道大家注意到?jīng)]有,前面我們說過程的時(shí)候,花了很多筆墨去說 HTML、說 CSS。相比之下,JS 的出鏡率也太低了點(diǎn)。

    工作說明書是工作分析的_瀏覽器工作原理是怎樣的_文獻(xiàn)檢索與應(yīng)用瀏覽是

    這當(dāng)然不是因?yàn)?JS 不重要。而是因?yàn)椋谑状武秩具^程中,JS 并不是一個(gè)非登場(chǎng)不可的角色——沒有 JS,CSSOM 和 DOM 照樣可以組成渲染樹,頁(yè)面依然會(huì)呈現(xiàn)——即使它死氣沉沉、毫無交互。

    JS 的作用在于修改,它幫助我們修改網(wǎng)頁(yè)的方方面面:內(nèi)容、樣式以及它如何響應(yīng)用戶交互。這“方方面面”的修改,本質(zhì)上都是對(duì) DOM 和 進(jìn)行修改。因此 JS 的執(zhí)行會(huì)阻止 CSSOM,在我們不作顯式聲明的情況下,它也會(huì)阻塞 DOM。

    我們通過一個(gè)?來理解一下這個(gè)機(jī)制:

    
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>JS阻塞測(cè)試title>
      <style>
        #container {
          background-color: yellow;
          width: 100px;
          height: 100px;
        }
      style>
      <script>
        // 嘗試獲取container元素
        var container = document.getElementById("container")
        console.log('container', container)
    

    文獻(xiàn)檢索與應(yīng)用瀏覽是_工作說明書是工作分析的_瀏覽器工作原理是怎樣的

    script> head> <body> <div id="container">div> <script> // 嘗試獲取container元素 var container = document.getElementById("container") console.log('container', container) // 輸出container元素此刻的背景色 console.log('container bgColor', getComputedStyle(container).backgroundColor) script> <style> #container { background-color: blue; } style> body> html>

    三個(gè) 的結(jié)果分別為:

    工作說明書是工作分析的_文獻(xiàn)檢索與應(yīng)用瀏覽是_瀏覽器工作原理是怎樣的

    注:本例僅使用了內(nèi)聯(lián) JS 做測(cè)試。感興趣的同學(xué)可以把這部分 JS 當(dāng)做外部文件引入看看效果——它們的表現(xiàn)一致。

    第一次嘗試獲取 id 為 的 DOM 失敗,這說明 JS 執(zhí)行時(shí)阻塞了 DOM,后續(xù)的 DOM 無法構(gòu)建;第二次才成功,這說明腳本塊只能找到在它前面構(gòu)建好的元素。這兩者結(jié)合起來,“阻塞 DOM”得到了驗(yàn)證。再看第三個(gè) ,嘗試獲取 CSS 樣式,獲取到的是在 JS 代碼執(zhí)行前的背景色(),而非后續(xù)設(shè)定的新樣式(blue),說明 CSSOM 也被阻塞了。那么在阻塞的背后,到底發(fā)生了什么呢?

    我們前面說過,JS 引擎是獨(dú)立于渲染引擎存在的。我們的 JS 代碼在文檔的何處插入,就在何處執(zhí)行。當(dāng) HTML 解析器遇到一個(gè) 標(biāo)簽時(shí),它會(huì)暫停渲染過程,將控制權(quán)交給 JS 引擎。JS 引擎對(duì)內(nèi)聯(lián)的 JS 代碼會(huì)直接執(zhí)行,對(duì)外部 JS 文件還要先獲取到腳本、再進(jìn)行執(zhí)行。等 JS 引擎運(yùn)行完畢,瀏覽器又會(huì)把控制權(quán)還給渲染引擎,繼續(xù) CSSOM 和 DOM 的構(gòu)建。 因此與其說是 JS 把 CSS 和 HTML 阻塞了瀏覽器工作原理是怎樣的,不如說是 JS 引擎搶走了渲染引擎的控制權(quán)。

    現(xiàn)在理解了阻塞的表現(xiàn)與原理,我們開始思考一個(gè)問題。瀏覽器之所以讓 JS 阻塞其它的活動(dòng),是因?yàn)樗恢?JS 會(huì)做什么改變,擔(dān)心如果不阻止后續(xù)的操作,會(huì)造成混亂。但是我們是寫 JS 的人,我們知道 JS 會(huì)做什么改變。假如我們可以確認(rèn)一個(gè) JS 文件的執(zhí)行時(shí)機(jī)并不一定非要是此時(shí)此刻,我們就可以通過對(duì)它使用 defer 和 async 來避免不必要的阻塞,這里我們就引出了外部 JS 的三種加載方式。

    JS的三種加載方式

    <script src="index.js">script>
    

    這種情況下 JS 會(huì)阻塞瀏覽器,瀏覽器必須等待 index.js 加載和執(zhí)行完畢才能去做其它事情。

    <script async src="index.js">script>
    

    async 模式下,JS 不會(huì)阻塞瀏覽器做任何其它的事情。它的加載是異步的,當(dāng)它加載結(jié)束,JS 腳本會(huì)立即執(zhí)行。

    <script defer src="index.js">script>
    

    defer 模式下,JS 的加載是異步的,執(zhí)行是被推遲的。等整個(gè)文檔解析完成、 事件即將被觸發(fā)時(shí),被標(biāo)記了 defer 的 JS 文件才會(huì)開始依次執(zhí)行。

    從應(yīng)用的角度來說,一般當(dāng)我們的腳本與 DOM 元素和其它腳本之間的依賴關(guān)系不強(qiáng)時(shí),我們會(huì)選用 async;當(dāng)腳本依賴于 DOM 元素和其它腳本的執(zhí)行結(jié)果時(shí),我們會(huì)選用 defer。

    通過審時(shí)度勢(shì)地向 標(biāo)簽添加 async/defer,我們就可以告訴瀏覽器在等待腳本可用期間不阻止其它的工作,這樣可以顯著提升性能。

    小結(jié)

    我們知道,當(dāng) JS 登場(chǎng)時(shí),往往意味著對(duì) DOM 的操作。DOM 操作所導(dǎo)致的性能開銷的“昂貴”,大家可能早就有所耳聞,雅虎軍規(guī)里很重要的一條就是“盡量減少 DOM 訪問”。

    其它前端性能優(yōu)化: 前端技術(shù)架構(gòu)體系(沒有鏈接的后續(xù)跟進(jìn)): 其它相關(guān)

    歡迎各位看官的批評(píng)和指正,共同學(xué)習(xí)和成長(zhǎng)

    希望該文章對(duì)您有幫助,你的 支持和鼓勵(lì)會(huì)是我持續(xù)的動(dòng)力

網(wǎng)站首頁(yè)   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號(hào):冀ICP備2024067069號(hào)-3 北京科技有限公司版權(quán)所有