成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

圖說 Firefox 全新 CSS 引擎

lsxiao / 885人閱讀

摘要:的主要組件包含了一個全新的引擎,稱為量子,也稱為。這個新引擎集成了四種不同瀏覽器的最新創(chuàng)新技術(shù),創(chuàng)造出一個全新的超級引擎。這可以發(fā)生在多個圖層上。最終,擁有最高特異性的規(guī)則會勝出。

原文:Inside a Super Fast CSS Engine: Quantum CSS(Aka Stylo), Lin Clark

注:原文發(fā)布于 2017 年 8 月,本文翻譯于 2018 年 4 月,因此對文中跟時間相關(guān)的部分內(nèi)容做了調(diào)整,但不影響核心內(nèi)容。

全新的 CSS 引擎 - Stylo

你可能已經(jīng)對量子項目(Project Quantum)有所耳聞,該項目對 Firefox 瀏覽器的內(nèi)部實現(xiàn)進行了重大重寫,以求更高性能。
本次重寫中,我們使用了并行瀏覽器引擎 Servo 的新技術(shù)。這里要介紹地是我們對瀏覽器引擎的重大改進。

該項目的開發(fā)過程就像是給正在飛行中的飛機更換引擎。對于瀏覽器中的各個組件,我們是逐個進行更改的。這樣,我們就可以在一個組件準備就緒后,立刻從 Firefox 中看到最新效果。

Servo 的主要組件包含了一個全新的 CSS 引擎,稱為量子 CSS(Quantum CSS,也稱為 Stylo)。

這個新引擎集成了四種不同瀏覽器的最新創(chuàng)新技術(shù),創(chuàng)造出一個全新的超級 CSS 引擎。

它充分利用了現(xiàn)代硬件多核心的特性,把所有的工作都變成了并行化操作。這使得它可以提速 2 ~ 4 倍,甚至最大能達到 18 倍。

在并行化的基礎(chǔ)上,它還結(jié)合了其他瀏覽器現(xiàn)有的最先進優(yōu)化技術(shù)。所以,即使拋開并行化運行技術(shù),它也仍然是個快速的 CSS 引擎。

這里,我們不禁要問,這個 CSS 引擎到底做了什么呢?
要回答這個問題,首先要知道 CSS 引擎是什么,它是如何跟瀏覽器其他組件一起工作的。然后,我們再看看 Stylo 是如何變得更快的。

CSS 引擎原理

CSS 引擎是瀏覽器渲染引擎(Rendering Engine)的重要組成部分。
渲染引擎的工作就是把網(wǎng)頁的 HTML 和 CSS 文件轉(zhuǎn)化為屏幕上顯示的像素點。

每個瀏覽器都有一個渲染引擎。Chrome 的稱為 Blink,Edge 的稱為 EdgeHTML,Safari 的稱為 WebKit,以及 Firefox 的稱為 Gecko 。

基本流程

要想把文件變?yōu)橄袼攸c,所有的渲染引擎基本上都會做以下相同的工作:

1、把文件解析成瀏覽器能理解的對象,包括 DOM 。從這個角度來說,DOM 掌握了整個頁面結(jié)構(gòu)。它知道每個元素之間的父子關(guān)系,但是它不知道這些元素具體長什么樣。

2、弄清楚每個元素應(yīng)該長什么樣。對于每個 DOM 節(jié)點,CSS 引擎首先會弄清楚應(yīng)該對它應(yīng)用什么 CSS 規(guī)則。然后,會計算出每個 CSS 屬性的值。

3、計算出每個節(jié)點的尺寸和它在屏幕上的位置。為每個要在屏幕上顯示的內(nèi)容創(chuàng)建盒模型。這些盒模型不僅僅用來表示 DOM 節(jié)點,它們也用來表示 DOM 節(jié)點的內(nèi)部內(nèi)容,比如一行一行的文本。

4、繪制不同的盒模型。這可以發(fā)生在多個圖層上。它就像是以前使用半透明紙的手繪動畫,每個圖層都是獨立的一張紙。這樣我們就可以只改變當前圖層的內(nèi)容,而不會影響到其他圖層的內(nèi)容。

5、取出已繪制的圖層,應(yīng)用任何僅包含合成器的屬性(比如變換),然后把它們合成為一張圖片。這就好比為這些疊加在一起的圖層拍一張照片,之后這張照片將會在屏幕上渲染出來。

從以上過程可以看出,當 CSS 引擎開始計算樣式時,它已經(jīng)得到了兩樣東西:

DOM 樹

樣式規(guī)則列表

引擎會逐個遍歷所有 DOM 節(jié)點,并計算出它們的樣式。這個過程中,它會給 DOM 節(jié)點的每個 CSS 屬性都進行求值,包括樣式表中沒有聲明的屬性。

這個過程就像一個人從頭到尾填一張表格一樣。CSS 引擎需要給每個 DOM 節(jié)點都填寫一張表格。并且,表格的每一處空白都需要填上值。

為了填這張表格,CSS 引擎需要做兩件事:

計算出每個節(jié)點應(yīng)該應(yīng)用什么樣式規(guī)則,即選擇器匹配(Selector Matching)

根據(jù)父節(jié)點或默認值計算出缺失的屬性值,即樣式級聯(lián)(Cascading)

選擇器匹配

在這個步驟中,CSS 引擎會把所有與 DOM 節(jié)點相匹配的樣式規(guī)則添加到一個列表中。
因為可能有多個樣式規(guī)則都匹配中,所以可能有多個相同的 CSS 屬性聲明。

此外,瀏覽器本身也提供了一些默認的樣式規(guī)則,即用戶代理樣式表。
那 CSS 引擎是如何確定應(yīng)該使用哪個值的呢?

這個時候就需要特異性規(guī)則(Specificity Rules)來幫忙了。
CSS 引擎會創(chuàng)建一個電子表格,然后根據(jù)不同的列對其進行排序。

最終,擁有最高特異性的規(guī)則會勝出。所以,基于這個表格,CSS 引擎就能夠填充那些它能夠填充的屬性值了。

對于不能使用這個方式計算出的值,它就會使用樣式級聯(lián)。

樣式級聯(lián)

樣式級聯(lián)讓 CSS 的編寫和維護都變得更加簡單。因為樣式級聯(lián),你可以在設(shè)置了 color 屬性后,直接就知道

、

  • 也將會使用你設(shè)置的顏色值(除非被重寫了)。

    為了找出級聯(lián)的樣式屬性,CSS 引擎會查看表格中的空白部分。
    如果屬性默認為繼承值,那么 CSS 引擎會沿著 DOM 樹往上查找,看看其祖先元素是否已經(jīng)設(shè)置了該值。
    如果所有的祖先元素都沒有設(shè)置該值,或者該屬性并不是繼承,那么就會使用默認值。

    至此,一個 DOM 節(jié)點的所有樣式屬性就都已經(jīng)得到計算值了。

    樣式結(jié)構(gòu)共享

    其實,上面提到的樣式表格與實際情形并不完全一致。
    CSS 擁有的樣式屬性非常多,達到上百個。如果 CSS 引擎針對每個 DOM 節(jié)點的屬性都保存一份樣式值,那么內(nèi)存將會被迅速耗盡。

    相反,CSS 引擎通常會使用樣式結(jié)構(gòu)共享(Style Struct Sharing)。
    它會把通常在一起使用的樣式值存儲于一個多帶帶的對象中,該對象稱為樣式結(jié)構(gòu)。
    然后,與其重新存儲相同對象上的所有樣式值,計算的樣式對象實際只保存了指向那個對象的指針。
    對于每個類別的樣式,實際上存儲的都是一個指向樣式結(jié)構(gòu)的指針。

    這種共享方式既省內(nèi)存又省時間。這樣的話,具有相似樣式的節(jié)點(比如兄弟節(jié)點)就只需要保存指向共享樣式結(jié)構(gòu)對象的指針即可。而且,由于很多屬性都是繼承來的,所以祖先節(jié)點可以跟所有的子孫節(jié)點共享相同的樣式結(jié)構(gòu)對象。

    優(yōu)化改進

    上面所說的就是優(yōu)化之前的樣式計算過程。

    這個過程中進行了很多計算工作。而且它不只是在第一個頁面加載的時候發(fā)生。它會在用戶與頁面進行交互的過程中反復的發(fā)生,懸停在元素上或者改變 DOM 結(jié)構(gòu),都會觸發(fā)樣式重算(Restyle)。

    也就是說,CSS 樣式計算是一個舉足輕重的待優(yōu)化點。而且在過去的 20 年里,各個瀏覽器一直都在測試使用不同的策略來優(yōu)化它。
    Stylo 充分吸收了來自不同引擎的優(yōu)化策略,然后把它們結(jié)合在一起,從而創(chuàng)造出一個全新的超級引擎。

    下面讓我們來看看 Stylo 的實現(xiàn)細節(jié)。

    并行運行

    Servo 是一個實驗版的瀏覽器,Stylo 就是該項目的一部分。Servo 想把渲染頁面所需的所有工作都進行并行化。
    并行化具體指什么呢?

    一臺計算機就像一個大腦。其中有一個部分是專門進行邏輯思考的,叫做算術(shù)邏輯單元(Arithmetic Logic Unit, ALU)。在 ALU 附近,排列著一些短期記憶存儲單元,稱為寄存器(Register)。ALU 和寄存器都是一起放在在 CPU 內(nèi)部的。當然也有用于長期記憶的存儲單元,稱為內(nèi)存(RAM)。

    使用這種 CPU 的早期計算機在同一時間只能進行一種事情。
    不過在過去的十幾年里,CPU 已經(jīng)進化到同時擁有多個 ALU 和寄存器組,具備了多個核心。
    這就意味著 CPU 可以一次進行多種事情,而且是同時進行的。

    Stylo 通過利用計算機的這種特性,把不同 DOM 節(jié)點的樣式計算過程分配到不同的計算核心當中。

    這看起來是一件很簡單的事情,只需要把 DOM 樹的不同分支分開來,然后交給不同的核心即可。但實際上做起來卻比想象的更加困難,其中一個原因就是 DOM 樹通常是不均勻的。這會導致有些核心做的工作會比其它的做得多很多。

    為了讓工作分配得更加均勻,Stylo 采用了一種稱為工作偷竊(Work Stealing)的技術(shù)。當處理一個 DOM 節(jié)點時,運行的代碼會把它的子節(jié)點分成一個或多個工作單元(Work Units)。這些工作單元會被添加到一個隊列中去。

    當某個核心把它的工作隊列都完成后,它會查看其它隊列中的工作單元,然后拿過來做。
    這樣的話,我們就可以把工作分配得更加均勻,而又不需要花費時間來遍歷 DOM 樹,也不需要事先就花費時間來計算該如何均勻地分配工作。

    在大多數(shù)的瀏覽器中,這種并行化工作做起來非常困難??偹苤⑿谢且粔K難啃的硬骨頭,而且 CSS 引擎非常復雜。同時, CSS 引擎還處于其他兩個最復雜部分: DOM 和布局的中間地帶。
    因此,這會非常容易引入 BUG ,而且并行化也會導致非常難以追查的 BUG,叫做數(shù)據(jù)競爭(Data Races)。我在另一篇文章中詳細介紹了這種類型錯誤,感興趣的可以參考下。

    如果你接受來自成百上千名工程師的代碼貢獻,你是如何做到平行編程而又無懼 BUG 的呢?這正是 Rust 的用武之地。

    在 Rust 中,你可以通過靜態(tài)檢查的方式來避免數(shù)據(jù)競爭。也就是說,你可以直接在代碼中就避免這種難以調(diào)試的錯誤。編譯器是不會讓你的代碼存在這樣的問題的。

    使用 Rust ,CSS 樣式計算就變成了所謂的完美并行問題,因為你基本上不用做什么就實現(xiàn)了并行化。這意味著我們的這個優(yōu)化可以達到線性增長。如果你的機器有 4 個核心,那么你就擁有接近 4 被的性能增長。

    規(guī)則樹

    對于每個 DOM 節(jié)點,CSS 引擎需要遍歷所有的樣式規(guī)則來完成選擇器匹配。
    但是對于大多數(shù)節(jié)點來說,這種匹配規(guī)則并不是改變的太頻繁。
    比如,如果用戶把光標懸停在某個父元素上,那么匹配中該元素的樣式規(guī)則就可能改變了。我們也需要重新計算它的后代元素的樣式,以重新處理那些繼承屬性。當然,匹配中這些后代元素的規(guī)則也可能是不變的。

    如果我們能夠記錄哪些規(guī)則能夠匹配中這些后代元素,那是極好的,這樣我們就不需要對它們重新進行選擇器匹配。這就是我們從 Firefox 上一代 CSS 引擎中借鑒過來的規(guī)則樹(Rule Tree)的原理。

    CSS 引擎會經(jīng)歷選擇器進行匹配的整個過程,然后按照特異性來排列它們,由此創(chuàng)建一個規(guī)則鏈表。

    該鏈表會被添加到規(guī)則樹中。

    CSS引擎會盡量使得規(guī)則樹的分支數(shù)量保持在最小值。為此,它會盡量復用已存在的規(guī)則分支。

    如果鏈表中的選擇器與已存在的分支相同,那么它將順著相同的路徑往下走。不過它可能最終會走到一個下一個規(guī)則不同的節(jié)點處,只有這個時候引擎才會新增一個分支。

    DOM 節(jié)點會取得指向這個規(guī)則最尾端節(jié)點的指針(這個例子中是 div#warning 規(guī)則)。而且,它的特異性最高的規(guī)則。

    在樣式重算時,CSS 引擎會進行一項快速檢查,以判斷對父元素的變更是否會影響匹配中子元素的規(guī)則。如果不影響,那么對于任何后代節(jié)點,引擎只需要順著后代節(jié)點保存的規(guī)則指針就可以找到對應(yīng)規(guī)則分支。在規(guī)則樹中,只要順著樹向上遍歷到根節(jié)點就可以獲取所有匹配的樣式規(guī)則。也就是說,CSS 引擎完全跳過了選擇器匹配和特異性排列過程。

    這樣我們就減少了樣式重算過程的計算量。
    雖然如此,但是在樣式初始化時還是會耗費大量計算。假如有 10,000 個節(jié)點,仍然需要進行 10,000 次選擇器匹配。
    不過,不用擔心,我們還有另一種方式來優(yōu)化它。

    樣式共享緩存

    對于一個擁有成千上萬個節(jié)點的頁面,其中有許多節(jié)點都會匹配中相同的樣式規(guī)則。
    舉例來說,對于一個很長的維基頁面,主要內(nèi)容區(qū)的段落應(yīng)該都是應(yīng)用相同的樣式規(guī)則,因此也就有相同的計算樣式。

    如果這里不做優(yōu)化的話,那么 CSS 引擎必須對每個段落都進行一次選擇器匹配和樣式計算。
    但是如果有一種方式能證明這些不同段落使用的是相同樣式的話,那么引擎就只需要做一次計算即可,然后其他段落節(jié)點都指向相同的計算樣式。

    這就是我們所說的樣式共享緩存(Style Sharing Cache),這種做法的靈感來自 Safari 和 Chrome 。
    當處理完一個節(jié)點之后,引擎會把計算樣式放進緩存。然后,在開始計算下一個節(jié)點的樣式之前,引擎會做一些檢查來判斷是否可以使用已緩存的樣式。

    這些檢查包括:

    兩個節(jié)點是否有相同的 id、class 等?如果是,那么它們可以匹配中相同的樣式規(guī)則。

    對于任何不是基于選擇器的樣式,比如內(nèi)聯(lián)樣式,節(jié)點具有相同的樣式值么?如果是,那么繼承自父節(jié)點的屬性不會被覆蓋,或者以相同的方式被覆蓋。

    節(jié)點的父節(jié)點是否指向相同的計算樣式對象?如果是,那么繼承的樣式值則是一樣的。

    從樣式共享緩存被提出的一開始,這些檢查就已經(jīng)應(yīng)用了。
    不過,隨著 CSS 的發(fā)展,有許多其它小場景會導致樣式共享緩存的檢查方式失效。
    比如,如果一個 CSS 規(guī)則使用了 :first-child 選擇器,那么兩個段落元素時就可能會導致樣式不一致,即使上面的那些檢查都認為它們是相同的。

    在 WebKit 和 Blink 中,樣式共享緩存會忽略這些場景,并且不使用緩存。
    隨著越來越多的網(wǎng)站使用現(xiàn)代選擇器,樣式共享緩存的優(yōu)化變得越來越雞肋,因此 Blink 團隊最終還是把它移除了。
    但是,事實證明樣式共享緩存還是有辦法跟上這些進化節(jié)奏的。

    在 Stylo 中,我們把記錄著所有這些現(xiàn)代選擇器并檢查他們是否能夠適用于 DOM 節(jié)點。然后,我們把檢查結(jié)果以 0 和 1 的方式存儲起來。如果兩個元素有相同的 0 和 1 ,那么我們就可以確定它們是匹配的。

    如果一個 DOM 節(jié)點可以使用已經(jīng)計算的樣式緩存,那么引擎就可以直接跳過大量的計算過程。由于頁面中經(jīng)常有大量的 DOM 節(jié)點擁有相同的樣式規(guī)則,所以樣式共享緩存不僅可以節(jié)省內(nèi)存,同時也能加快計算過程。

    結(jié)論

    Stylo 是第一個從 Servo 遷移到 Firefox 的大型技術(shù)。
    在這個過程中,我們已經(jīng)學到了很多關(guān)于如何把使用 Rust 編寫現(xiàn)代高性能代碼集成到 Firefox 核心。

    事不宜遲,趕緊下載 Firefox ,體驗極速吧!

  • 文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/113102.html

    相關(guān)文章

    • 圖說 WebAssembly(六):現(xiàn)狀與展望

      摘要:現(xiàn)狀年月日,主流的四大瀏覽器達成了共識并宣布的最小可行產(chǎn)品已經(jīng)完成。更快的函數(shù)調(diào)用當前,在中調(diào)用函數(shù)比想象的要慢。直接操作目前,沒有任何方式能夠操作。這就導致了部分應(yīng)用可能會因此而推遲發(fā)布時間。結(jié)束現(xiàn)如今已經(jīng)相當快速。 本文是圖說 WebAssembly 系列文章的最后一篇。如果您還未閱讀之前的文章,建議您從第一篇入手。 現(xiàn)狀 2017 年 2 月 28 日,主流的四大瀏覽器達成了共識...

      clasnake 評論0 收藏0
    • 圖說 WebAssembly(二):JIT 編譯器

      摘要:編譯器優(yōu)缺點與解釋器相比,編譯器有著相反的優(yōu)缺點。它們?yōu)橐嫘略隽艘粋€組件,稱為監(jiān)視器,或者。優(yōu)化編譯器會基于監(jiān)視器記錄的代碼運行信息來作出一些判斷。通常來說,優(yōu)化編譯器會使得代碼跑的更快。而這正是優(yōu)化編譯器所做的優(yōu)化之一。 本文是圖說 WebAssembly 系列文章的第二篇,如果你還沒閱讀其它的,建議您從第一篇開始。 JavaScript 的運行,一開始是很慢的,但是后面會變得越來...

      LuDongWei 評論0 收藏0
    • 圖說 WebAssembly(一):序言

      摘要:性能簡史在年,被創(chuàng)造出來時并不是沖著性能去的。而且在之后的十年發(fā)展中,它的性能一直是很低的。的引入成就了性能提升的一個轉(zhuǎn)折點,其執(zhí)行速度比以往快了之多。性能提升也使得在全新的問題上使用成為可能?,F(xiàn)在,極可能是下一個性能轉(zhuǎn)折點。 你可能已經(jīng)聽說 WebAssembly 代碼跑起來非??臁5悄阒肋@是為什么嗎?在本系列文章中,我們將探究其原因。 何為 WebAssembly WebAss...

      codergarden 評論0 收藏0
    • 瀏覽器內(nèi)核、JS 引擎、頁面呈現(xiàn)原理及其優(yōu)化

      摘要:瀏覽器內(nèi)核又叫渲染引擎,主要負責的解析,頁面布局渲染與復合層合成。頁面呈現(xiàn)原理規(guī)范定義了的詞法及語法文法。解析器使用和解析生成器從語法文件中自動生成解析器?;貞浺幌陆馕銎鞯慕榻B,創(chuàng)建一個自底向上的解析器,使用自頂向下解析器。 瀏覽器內(nèi)核又叫渲染引擎,主要負責 HTML、CSS 的解析,頁面布局、渲染與復合層合成。瀏覽器內(nèi)核的不同帶來的主要問題是對 CSS 的支持度與屬性表現(xiàn)差異。 we...

      wean 評論0 收藏0
    • 瀏覽器內(nèi)核、JS 引擎、頁面呈現(xiàn)原理及其優(yōu)化

      摘要:瀏覽器內(nèi)核又叫渲染引擎,主要負責的解析,頁面布局渲染與復合層合成。頁面呈現(xiàn)原理規(guī)范定義了的詞法及語法文法。解析器使用和解析生成器從語法文件中自動生成解析器?;貞浺幌陆馕銎鞯慕榻B,創(chuàng)建一個自底向上的解析器,使用自頂向下解析器。 瀏覽器內(nèi)核又叫渲染引擎,主要負責 HTML、CSS 的解析,頁面布局、渲染與復合層合成。瀏覽器內(nèi)核的不同帶來的主要問題是對 CSS 的支持度與屬性表現(xiàn)差異。 we...

      zlyBear 評論0 收藏0

    發(fā)表評論

    0條評論

    閱讀需要支付1元查看
    <