一探瀏覽器幕後的《三倆事》上一篇的介紹讓你們對瀏覽器的組成有了個模糊的認識:css
今天呢作渲染模塊(WebKit)展開學習討論。html
首先做爲順序介紹來講。我應該具體介紹實現一個瀏覽器應該包含哪些內容(介紹一下chromium
實現包含了哪些內容)。可是考慮在前端
話題的介紹。只作簡單的列舉不作具體展開討論;有興趣能夠自行下去學習。前端
其次按你們耳熟能詳的程度來講的話我應該着重討論一下JS引擎(V8 event-loop相關)
;可是本節內容仍是想先介紹討論一下渲染引擎(WebKit)
。不爲別的我就是喜歡玩~ 由於我寫這個系列的受衆仍是偏向前端,因此涉及到須要代碼介入講解的部分這邊採起JavaScript
來實現。node
畫架構圖畫習慣了,不要在乎醜陋的細節 - -.
由上圖能夠獲得渲染引擎內部解析執行大概過程的信息:
下面對於上文所提部分進行展開討論一下 flow me~ gogogo!web
上面Parser的字眼是否是太多了。咱們獲得一個信息解析是渲染引擎中很是重要的一個環節,因此首先須要介紹一下解析.正則表達式
解析文檔是指將文檔轉化成爲有意義的結構,也就是可以讓代碼理解和使用的結構。解析獲得的結果一般是表明了文檔結構的節點樹,它稱做解析樹或者語法樹。編程
解析是以文檔所遵循的語法規則(編寫文檔所用的語言或格式)爲基礎的。比方說HTML解析那麼是在HTML4/5的規範上進行的。全部能夠解析的格式都必須對應肯定的語法(由詞彙和語法規則構成)。canvas
解析過程一般是分紅兩個子過程:詞法分析和語法分析。
詞法分析是將輸入內容分割成大量標記的過程。(進行切分可識別大量標記的詞段)語法分析是應用語言的語法規則的過程(到底這段語言是要作什麼工做)。segmentfault
HTML 解析器的任務是將 HTML 標記解析成解析樹。瀏覽器
HTML 語法定義:
HTML 的詞彙和語法在 W3C 組織建立的規範中進行了定義。
DOM
解析器的輸出「解析樹」是由 DOM 元素和屬性節點構成的樹結構。DOM 是文檔對象模型 (Document Object Model) 的縮寫。它是 HTML
文檔的對象表示,同時也是外部內容(例如 JavaScript)與 HTML 元素之間的接口。
解析樹的根節點是Document
對象。
DOM解析code示意(不能運行的) 首先要了解解析過程必定是迭代過程:
// 分析標記<>和屬性的正則表達式 var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[\w-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/, endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/, attr = /([-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; function ParserHTML(html){ // 接收參數html while(html){ // 匹配註釋內容 if(html.indexOf("<!--") == 0){ // } // 匹配開始標籤 if (html.indexOf("<") == 0) { match = html.match(startTag); if (match) { html = html.substring(match[0].length); //匹配截取 //繼續迭代 } } if(html.indexOf("</") == 0){ //匹配結束標籤操做 } } } // 輸出示意結構 { element:"", parentNode:{}, childrenNode:{}, content:"", .... } // 我以前寫的找不到了--, 你們能夠試着去實現一下。有問題隨時溝通 本示例正則可用。
CSS解析同HTML不一樣地方是上下文無關的語法;可經過不少解析器作解析。
詞法語法(詞彙)是針對各個標記用正則表達式定義的:
comment \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num [0-9]+|[0-9]*"."[0-9]+
nonascii [\200-\377]
nmstart [_a-z]|{nonascii}|{escape}
nmchar [_a-z0-9-]|{nonascii}|{escape}
name {nmchar}+
ident {nmstart}{nmchar}*
在 DOM 樹構建的同時,瀏覽器還會構建另外一個樹結構:渲染樹。這是由可視化元素按照其顯示順序而組成的樹,也是文檔的可視化表示。它的做用是讓您按照正確的順序繪製內容。
WebKits RenderObject 類是全部渲染樹的基類,其定義以下:
class RenderObject{ virtual void layout(); //佈局 virtual void paint(PaintInfo); //繪製 virtual void rect repaintRect(); //從新繪製Rect Node* node; // DOM節點 RenderStyle* style; // 計算render style RenderLayer* containgLayer; //render layer }
渲染樹是和 DOM 元素相對應的,但並不是一一對應。非可視化的 DOM 元素不會插入渲染樹中,例如「head」元素。若是元素的 display 屬性值爲「none」,那麼也不會顯示在渲染樹中(可是 visibility 屬性值爲「hidden」的元素仍會顯示)。
關於多渲染樹的例子是格式無效的 HTML。根據 CSS 規範,inline 元素只能包含 block 元素或 inline 元素中的一種。若是出現了混合內容,則應建立匿名的 block 渲染樹,以包裹 inline 元素。
有一些渲染對象對應於 DOM 節點,但在樹中所在的位置與 DOM 節點不一樣。浮動定位和絕對定位的元素就是這樣,它們處於正常的流程以外,放置在樹中的其餘地方,並映射到真正的框架,而放在原位的是佔位框架。
建立完成渲染樹時,並不包含位置和大小信息。計算這些值的過程稱爲佈局或重排。
HTML 採用基於流的佈局模型,這意味着大多數狀況下只要一次遍歷就能計算出幾何信息。處於流中靠後位置元素一般不會影響靠前位置元素的幾何特徵,所以佈局能夠按從左至右、從上至下的順序遍歷文檔。可是也有例外狀況,好比 HTML 表格的計算就須要不止一次的遍歷 (3.5)。
座標系是相對於根框架而創建的,使用的是上座標和左座標。
佈局是一個遞歸的過程。它從根渲染樹(對應於 HTML 文檔的 <html> 元素)開始,而後遞歸遍歷部分或全部的框架層次結構,爲每個須要計算的渲染樹計算幾何信息。
根渲染樹的位置左上角 是 0,0
,(跟canvas2D座標規則一致)其尺寸爲視口(也就是瀏覽器窗口的可見區域)。
全部的渲染樹都有一個layout
或者reflow
方法,每個渲染樹將會調用其須要進行佈局的子代的 layout
方法。
在繪製階段,系統會遍歷渲染樹,並調用渲染樹的paint
方法,將渲染樹的內容顯示在屏幕上。繪製工做是使用用戶界面基礎組件完成的。
繪製的順序其實就是元素進入堆棧樣式上下文的順序;從後向前。塊渲染樹的堆棧順序以下:
繪製實現可參考canvas
(canvas必定要學的啊 時刻關注一些前沿的動做
),瞭解基礎圖元繪製方法與過程。例如繪製line
(須要座標 基礎圖元結構等等):
距離上一篇文章的生活日記: 20210521那天呢照樣開心(朋友圈依舊不活躍)。20210522呢不開心。20210523也就是今天總的來講過得去 並無學習。(勞逸結合 哈哈)
而後呢由於最近有人總微信我編程範式到底選擇哪一種好一點呢? 我如今用的更可能是什麼編程範式呢? 本身寫代碼維護起來好睏難怎麼辦呢?... (作了好久的解答,應該記錄下來提供給你們)下期JS引擎以前 我會把編程範式作一個簡單介紹供你們參考 小小插曲(預計明天)。
加油!有問題請你們隨時留言,看到必定會回覆的。對於上篇補架構圖...好吧是我鴿了 我看也沒人催..懶得畫了