整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          淺談從瀏覽器輸入U(xiǎn)RL到頁面渲染的流程

          淺談從瀏覽器輸入U(xiǎn)RL到頁面渲染的流程

          覽器輸入U(xiǎn)RL到頁面渲染完成,這個過程大致可分為兩個階段:網(wǎng)絡(luò)通信和頁面渲染。

          一、網(wǎng)絡(luò)通信

          互聯(lián)網(wǎng)內(nèi)各網(wǎng)絡(luò)間設(shè)備的通信遵循TCP/IP協(xié)議,利用TCP/IP協(xié)議進(jìn)行網(wǎng)絡(luò)通信時,會通過分層與對方通信。數(shù)據(jù)傳輸?shù)倪^程:由應(yīng)用層產(chǎn)生數(shù)據(jù)后,經(jīng)過傳輸層的分段處理(添加TCP或UDP包頭)、網(wǎng)絡(luò)層(添加IP地址信息)、數(shù)據(jù)鏈路層(封裝成MAC幀)、物理層傳輸電信號。


          ??

          覽器渲染過程

          瀏覽器主要組件結(jié)構(gòu)

          (瀏覽器主要組件)

          渲染引擎——webkit和GeckoFirefox使用Geoko——Mozilla自主研發(fā)的渲染引擎。

          Safari和Chrome都使用webkit。Webkit是一款開源渲染引擎,它本來是為linux平臺研發(fā)的,后來由Apple移植到Mac及Windows上。

          本文我主要以webkit渲染引擎來講解,盡管webkit和Gecko使用的術(shù)語稍有不同,他們的主要流程基本相同。

          (webkit渲染引擎流程)

          關(guān)鍵渲染路徑關(guān)鍵渲染路徑是指瀏覽器從最初接收請求來的HTML、CSS、javascript等資源,然后解析、構(gòu)建樹、渲染布局、繪制,最后呈現(xiàn)給客戶能看到的界面這整個過程。

          所以瀏覽器的渲染過程主要包括以下幾步:

          解析HTML生成DOM樹。解析CSS生成CSSOM規(guī)則樹。將DOM樹與CSSOM規(guī)則樹合并在一起生成渲染樹。遍歷渲染樹開始布局,計(jì)算每個節(jié)點(diǎn)的位置大小信息。將渲染樹每個節(jié)點(diǎn)繪制到屏幕。

          構(gòu)建DOM樹當(dāng)瀏覽器接收到服務(wù)器響應(yīng)來的HTML文檔后,會遍歷文檔節(jié)點(diǎn),生成DOM樹。

          需要注意的是,DOM樹的生成過程中可能會被CSS和JS的加載執(zhí)行阻塞。渲染阻塞問題下文會講。

          構(gòu)建CSSOM規(guī)則樹瀏覽器解析CSS文件并生成CSS規(guī)則樹,每個CSS文件都被分析成一個StyleSheet對象,每個對象都包含CSS規(guī)則。CSS規(guī)則對象包含對應(yīng)于CSS語法的選擇器和聲明對象以及其他對象。

          渲染阻塞當(dāng)瀏覽器遇到一個 script 標(biāo)記時,DOM 構(gòu)建將暫停,直至腳本完成執(zhí)行,然后繼續(xù)構(gòu)建DOM。每次去執(zhí)行JavaScript腳本都會嚴(yán)重地阻塞DOM樹的構(gòu)建,如果JavaScript腳本還操作了CSSOM,而正好這個CSSOM還沒有下載和構(gòu)建,瀏覽器甚至?xí)舆t腳本執(zhí)行和構(gòu)建DOM,直至完成其CSSOM的下載和構(gòu)建。

          所以,script 標(biāo)簽的位置很重要。實(shí)際使用時,可以遵循下面兩個原則:

          CSS 優(yōu)先:引入順序上,CSS 資源先于 JavaScript 資源。JS置后:我們通常把JS代碼放到頁面底部,且JavaScript 應(yīng)盡量少影響 DOM 的構(gòu)建。

          當(dāng)解析html的時候,會把新來的元素插入dom樹里面,同時去查找css,然后把對應(yīng)的樣式規(guī)則應(yīng)用到元素上,查找樣式表是按照從右到左的順序去匹配的。

          例如: div p {font-size: 16px},會先尋找所有p標(biāo)簽并判斷它的父標(biāo)簽是否為div之后才會決定要不要采用這個樣式進(jìn)行渲染)。所以,我們平時寫CSS時,盡量用id和class,千萬不要過渡層疊。

          構(gòu)建渲染樹通過DOM樹和CSS規(guī)則樹我們便可以構(gòu)建渲染樹。瀏覽器會先從DOM樹的根節(jié)點(diǎn)開始遍歷每個可見節(jié)點(diǎn)。對每個可見節(jié)點(diǎn),找到其適配的CSS樣式規(guī)則并應(yīng)用。

          渲染樹構(gòu)建完成后,每個節(jié)點(diǎn)都是可見節(jié)點(diǎn)并且都含有其內(nèi)容和對應(yīng)規(guī)則的樣式。這也是渲染樹與DOM樹的最大區(qū)別所在。渲染樹是用于顯示,那些不可見的元素當(dāng)然就不會在這棵樹中出現(xiàn)了,譬如。除此之外,display等于none的也不會被顯示在這棵樹里頭,但是visibility等于hidden的元素是會顯示在這棵樹里頭的。

          渲染樹布局布局階段會從渲染樹的根節(jié)點(diǎn)開始遍歷,然后確定每個節(jié)點(diǎn)對象在頁面上的確切大小與位置,布局階段的輸出是一個盒子模型,它會精確地捕獲每個元素在屏幕內(nèi)的確切位置與大小。

          渲染樹繪制在繪制階段,遍歷渲染樹,調(diào)用渲染器的paint()方法在屏幕上顯示其內(nèi)容。渲染樹的繪制工作是由瀏覽器的UI后端組件完成的。

          reflow與repaint:根據(jù)渲染樹布局,計(jì)算CSS樣式,即每個節(jié)點(diǎn)在頁面中的大小和位置等幾何信息。HTML默認(rèn)是流式布局的,CSS和js會打破這種布局,改變DOM的外觀樣式以及大小和位置。這時就要提到兩個重要概念:replaint和reflow。

          replaint:屏幕的一部分重畫,不影響整體布局,比如某個CSS的背景色變了,但元素的幾何尺寸和位置不變。reflow:意味著元件的幾何尺寸變了,我們需要重新驗(yàn)證并計(jì)算渲染樹。是渲染樹的一部分或全部發(fā)生了變化。這就是Reflow,或是Layout。

          所以我們應(yīng)該盡量減少reflow和replaint,我想這也是為什么現(xiàn)在很少有用table布局的原因之一。

          display:none 會觸發(fā) reflow,visibility: hidden屬性并不算是不可見屬性,它的語義是隱藏元素,但元素仍然占據(jù)著布局空間,它會被渲染成一個空框,所以visibility:hidden 只會觸發(fā) repaint,因?yàn)闆]有發(fā)生位置變化。

          有些情況下,比如修改了元素的樣式,瀏覽器并不會立刻 reflow 或 repaint 一次,而是會把這樣的操作積攢一批,然后做一次 reflow,這又叫異步 reflow 或增量異步 reflow。

          有些情況下,比如 resize 窗口,改變了頁面默認(rèn)的字體等。對于這些操作,瀏覽器會馬上進(jìn)行 reflow。

          的想法:如果我要構(gòu)建快速可靠網(wǎng)站,需要真正了解瀏覽器渲染網(wǎng)頁的每個步驟機(jī)制,這樣就可以在開發(fā)過程中對每個步驟進(jìn)行優(yōu)化。這篇文章是我在較高水平上對端到端過程的學(xué)習(xí)總結(jié)。

          好了,廢話不多說,我們開始吧。這個過程可以分為以下幾個主要階段:

          1. 開始解析HTML
          2. 獲取外部資源
          3. 解析 CSS 并構(gòu)建CSSOM
          4. 執(zhí)行 JavaScript
          5. 合并 DOM 和 CSSOM 以構(gòu)造渲染樹
          6. 計(jì)算布局和繪制

          1.開始解析HTML

          當(dāng)瀏覽器通過網(wǎng)絡(luò)接收頁面的HTML數(shù)據(jù)時,它會立即設(shè)置解析器將HTML轉(zhuǎn)換為文檔對象模型(DOM)

          文檔對象模型 (DOM) 是HTML和XML文檔的編程接口。它提供了對文檔的結(jié)構(gòu)化的表述,并定義了一種方式可以使從程序中對該結(jié)構(gòu)進(jìn)行訪問,從而改變文檔的結(jié)構(gòu),樣式和內(nèi)容。DOM 將文檔解析為一個由節(jié)點(diǎn)和對象(包含屬性和方法的對象)組成的結(jié)構(gòu)集合。簡言之,它會將web頁面和腳本或程序語言連接起來。

          解析過程的第一步是將HTML分解并表示為開始標(biāo)記結(jié)束標(biāo)記及內(nèi)容標(biāo)記,然后它可以構(gòu)造DOM。

          2. 獲取外部資源

          當(dāng)解析器遇到外部資源(如CSS或JavaScript文件)時,解析器將提取這些文件。解析器在加載CSS文件時繼續(xù)運(yùn)行,此時會阻止頁面渲染,直到資源加載解析完(稍后會詳細(xì)介紹)。

          JavaScript 文件略有不同-默認(rèn)情況下,解析器會在加載 JS 文件然后進(jìn)行解析同時會阻止對HTML的解析。可以將兩個屬性添加到腳本標(biāo)簽中以減輕這種情況:defer 和async。兩者都允許解析器在后臺加載JavaScript 文件的同時繼續(xù)運(yùn)行,但是它們的執(zhí)行方式不同。關(guān)于這一點(diǎn)后面還會再講一點(diǎn),但總的來說:

          defer表示文件的執(zhí)行將被延遲,直到文檔的解析完成為止。如果多個文件具有defer屬性,則將按照頁面放置的順序依次執(zhí)行。

          <script type="text/javascript" src="script.js" defer>
          

          async 意味著文件將在加載后立即執(zhí)行,這可能是在解析過程中或在解析過程之后執(zhí)行的,因此不能保證異步腳本的執(zhí)行順序。

          <script type="text/javascript" src="script.js" async>
          

          預(yù)加載資源

          <link> 元素的 rel 屬性的屬性值preload能夠讓你在你的HTML頁面中 <head>元素內(nèi)部書寫一些聲明式的資源獲取請求,可以指明哪些資源是在頁面加載完成后即刻需要的。

          對于這種即刻需要的資源,你可能希望在頁面加載的生命周期的早期階段就開始獲取,在瀏覽器的主渲染機(jī)制介入前就進(jìn)行預(yù)加載。這一機(jī)制使得資源可以更早的得到加載并可用,且更不易阻塞頁面的初步渲染,進(jìn)而提升性能。

          <link href="style.css" rel="preload" as="style" />
          

          3.解析CSS并構(gòu)建CSSOM

          你可能很早就知道DOM,但對**CSSOM(CSS對象模型)**可能聽得少,反正我也沒聽過幾次。

          CSS 對象模型 (CSSOM) 是樹形形式的所有CSS選擇器和每個選擇器的相關(guān)屬性的映射,具有樹的根節(jié)點(diǎn),同級,后代,子級和其他關(guān)系。CSSOM 與 文檔對象模型(DOM) 非常相似。兩者都是關(guān)鍵渲染路徑的一部分,也是正確渲染一個網(wǎng)站必須采取的一系列步驟。

          CSSOM 與 DOM一起構(gòu)建渲染樹,瀏覽器依次使用渲染樹來布局和繪制網(wǎng)頁。

          與HTML文件和DOM相似,加載CSS文件時,必須將它們解析并轉(zhuǎn)換為樹-這次是CSSOM。它描述了頁面上的所有CSS選擇器,它們的層次結(jié)構(gòu)和屬性。

          CSSOM 與 DOM的不同之處在于它不能以增量方式構(gòu)建,因?yàn)镃SS規(guī)則由于特定性而可以在各個不同的點(diǎn)相互覆蓋。這就是CSS 阻塞渲染的原因,因?yàn)樵诮馕鏊蠧SS并構(gòu)建CSSOM之前,瀏覽器無法知道每個元素在屏幕上的位置。

          4.執(zhí)行JavaScript

          不同的瀏覽器有不同的 JS 引擎來執(zhí)行此任務(wù)。從計(jì)算機(jī)資源的角度來看,解析 JS 可能是一個昂貴的過程,比其他類型的資源更昂貴,因此優(yōu)化它對于獲得良好的性能是如此重要。

          載入事件

          加載的JS和DOM被完全解析并準(zhǔn)備就緒后就會 emit document.DOMContentLoaded事件。對于需要訪問DOM的任何腳本,例如以某種方式進(jìn)行操作或偵聽用戶交互事件,優(yōu)良作法是在執(zhí)行腳本之前先等待此事件。

          document.addEventListener('DOMContentLoaded', (event) => {
              // 這里面可以安全地訪問DOM了
          });
          

          在所有其他內(nèi)容(例如異步JavaScript,圖像等)完成加載后,將觸發(fā)window.load事件。

          window.addEventListener('load', (event) => {
              // 頁面現(xiàn)已完全加載
          });
          

          5.合并DOM和CSSOM 構(gòu)建渲染樹

          渲染樹DOMCSSOM的組合,表示將要渲染到頁面上的所有內(nèi)容。這并不一定意味著渲染樹中的所有節(jié)點(diǎn)都將在視覺上呈現(xiàn),例如,將包含opacity: 0或visibility: hidden的樣式的節(jié)點(diǎn),并仍然可以被屏幕閱讀器等讀取,而display: none不包括任何內(nèi)容。此外,諸如<head>之類的不包含任何視覺信息的標(biāo)簽將始終被忽略。

          與 JS 引擎一樣,不同的瀏覽器具有不同的渲染引擎。

          6. 計(jì)算布局和繪制

          現(xiàn)在我們有了完整的渲染樹,瀏覽器知道了要渲染什么,但是不知道在哪里渲染。因此,必須計(jì)算頁面的布局(即每個節(jié)點(diǎn)的位置和大小)。渲染引擎從頂部開始一直向下遍歷渲染樹,計(jì)算應(yīng)顯示每個節(jié)點(diǎn)的坐標(biāo)。

          完成之后,最后一步是獲取布局信息并將像素繪制到屏幕上。


          作者:James Starkie 譯者:前端小智 來源:dev

          原文:https://dev.to/jstarmx/how-the-browser-renders-a-web-page-1ah


          主站蜘蛛池模板: 午夜视频久久久久一区| 冲田杏梨高清无一区二区| 秋霞午夜一区二区| 亚洲一区在线视频观看| 免费看AV毛片一区二区三区| 成人无码一区二区三区| 国产精品亚洲专一区二区三区| 亚洲一区中文字幕久久| 久久国产精品免费一区| 韩国福利影视一区二区三区| 中文字幕精品无码一区二区三区| 痴汉中文字幕视频一区| 精品一区二区三区在线观看l| 美女福利视频一区| 国产精品一区二区av| 一区五十路在线中出| 无码人妻精品一区二区三区不卡| 一区二区免费在线观看| 日韩在线一区高清在线| 国内精品视频一区二区三区| 日本无码一区二区三区白峰美| 成人中文字幕一区二区三区| 亚洲va乱码一区二区三区| 久久久老熟女一区二区三区| 精品一区二区三区无码免费视频 | 国产精品区一区二区三在线播放 | 国产精品成人99一区无码| 中文字幕av人妻少妇一区二区| 亚州AV综合色区无码一区| 另类国产精品一区二区| 人妻视频一区二区三区免费| 天美传媒一区二区三区| 日美欧韩一区二去三区| 精品人妻一区二区三区四区在线| 国产精品香蕉在线一区| 极品少妇伦理一区二区| 久久精品国产第一区二区| 成人日韩熟女高清视频一区| 波多野结衣免费一区视频 | 末成年女AV片一区二区| 亚无码乱人伦一区二区|