一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

作者 : 开心源码 本文共4456个字,预计阅读时间需要12分钟 发布时间: 2022-05-11 共77人阅读

您可可以已经听说过Project Quantum …它是Firefox的内部部件的重大改写,使Firefox快速。我们正在从我们的试验浏览器Servo中进行部分交换,并对引擎的其余部分进行了大量改进。

该项目已经与喷气式飞机仍在飞行中替换喷气发动机相比较。我们正在按组件进行更改,以便在每个组件准备就绪后,您能在Firefox中看到效果。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

而Servo的第一个主要组件 – 名为Quantum CSS(以前称为Stylo)的新CSS引擎 – 现在能在我们的Nightly版本中进行测试。您能通过转到about:config并设置layout.css.servo.enabled为true 来确保它已打开。

这款新引擎将来自四个不同浏览器的最先进的创新融合在一起,以创立一个新的超级CSS引擎。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

它利使用了现代硬件,并行化了机器中所有内核的工作。这意味着它最多能运行2或者4甚至18倍。

除此之外,它结合了来自其余浏览器的现有最新优化。所以即便没有并行运行,它依然是一个快速的CSS引擎。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

但是什么是CSS引擎呢?首先,我们来看看CSS引擎,以及它如何适应浏览器的其他部分。那么我们能看看Quantum CSS如何使它更快。

什么是CSS引擎?

CSS引擎是浏览器渲染引擎的一部分。渲染引擎采使用网站的HTML和CSS文件,并将其转换为屏幕上的像素。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

每个浏览器都有一个渲染引擎。在Chrome中,它叫做Blink。在Edge中,它被称为EdgeHTML。在Safari中,它被称为WebKit。在Firefox中,它被称为Gecko。

要从文件到像素,所有这些渲染引擎基本上都做同样的事情:

  1. 将文件解析为浏览器能了解的对象,包括DOM。在这一点上,DOM知道页面的结构。它知道元素之间的父/子关系。不知道这些元素应该是什么样的。

  2. 找出这些元素应该是什么样的。对于每个DOM节点,CSS引擎都会确定哪些CSS规则适使用。而后,它会为该DOM节点的每个CSS属性确定值。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

  1. 绘出每个节点的尺寸及其在屏幕上的位置。将为屏幕上显示的每个东西创立框。这些方框不仅仅代表DOM节点,还能为DOM节点内的东西,如文本行。

一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

  1. 画不同的盒子。这可可以发生在多层。我想起了这个像老式的手绘动画,带有洋葱的纸层。这样即可以改变一个层,而不必在其余层上重绘某些东西。

  2. 拿这些不同的绘图层,应使用任何只有合成器的属性,如transforms,并将它们变成一个图像。这基本上就像是将层叠在一起的图片。此图像将在屏幕上呈现。

这意味着当它开始计算样式时,CSS引擎有两件事情:

  • 一个DOM树

  • 风格规则清单

它一一浏览每个DOM节点,并计算出该DOM节点的样式。作为其中的一部分,它为DOM节点提供了每个CSS属性的值,即便样式表未公告该属性的值。

我想像这样像一个人通过填写一个表单。他们需要为每个DOM节点填写这些表单之一。而对于每个表格领域,他们需要有一个答案。

要做到这一点,CSS引擎需要做两件事情:

  • 找出哪些规则适使用于节点 – aka 选择器匹配

  • 用父级值或者默认值(也称为级联)填充当何缺少的值

选择器匹配

对于此步骤,我们将增加与DOM节点匹配的任何规则到列表。由于多个规则能匹配,所以同一属性可可以有多个公告。

此外,浏览器本身还增加了少量默认的CSS(称为使用户代理商样式表)。CSS引擎知道要选择哪个值?

这就是特定性规则的出现。CSS引擎基本上创立一个电子表格。而后它根据不同的列对公告进行排序。

具备最高特异性的规则胜出。所以基于这个电子表格,CSS引擎填写了它能的值。

对于其他的,我们将用级联。

级联

级联使得CSS易于编写和维护。由于级联,能设置color在机身性可以和知道该文本p,并spanli元素都将用该颜色(除非你有一个更具体的覆盖)。

为此,CSS引擎会查看其表单上的空白框。假如该属性默认继承,那么CSS引擎将向上爬树,以查看其中一个祖先能否具备值。假如没有一个祖先有一个值,或者者该属性不继承,它将取得一个默认值。

所以现在所有的样式都已经为这个DOM节点计算了。

一个sidenote:风格结构共享

我向你展现的形式有点虚伪。CSS有数以百计的属性。假如CSS引擎持有每个DOM节点的每个属性的值,它将很快耗尽内存。

相反,引擎通常会做少量所谓的样式结构共享。它们通常在一起被称为样式结构的不同对象中存储数据(如字体属性)。而后,代替在同一对象中拥有所有属性,计算的样式对象只有指针。对于每个类别,都有一个指向具备该DOM节点正确值的样式结构的指针。

这将节省内存和时间。具备相似属性的节点(如兄弟姐妹)能指向与它们共享的属性相同的结构体。并且由于许多属性都被继承,所以祖先能与没有指定自己的覆盖的任何后代共享一个结构体。

现在,我们如何做到这一点呢?

那么当你没有优化它时,这就是什么样的计算。

这里有很多工作。它不仅仅需要在第一页的加载中发生。当使用户与页面进行交互,将鼠标悬停在元素上或者对DOM进行更改时,会重复出现,从而触发重新启动。

这意味着CSS样式计算是优化的最佳选择…而浏览器已经测试出不同的策略,以优化它在过去20年。什么Quantum CSS做的是从不同的引擎中充分利使用这些策略,并结合它们来创立一个超快的新引擎。

所以我们来看看这些工作如何共同的细节。

并行运行

Servo项目(Quantum CSS来自)是一个试验浏览器,它试图并行化渲染网页的所有不同部分。这意味着什么?

一台电脑就像一只大脑。有一部分做这个想法(ALU)。在这个周围,有少量短期记忆(寄存器)。这些在CPU上组合在一起。那么长期的内存是RAM。

早期的电脑一次只可以使用这种CPU来思考一件事情。但是在过去十年中,CPU已经转移到拥有多个ALU和寄存器,分组在一起。这意味着CPU能一次思考多个东西 – 并行。

Quantum CSS通过分散不同核心上的不同DOM节点的样式计算来利使用计算机的最新功可以。

这似乎是一件容易的事情,只要拆分树的分支,并在不同的核心上进行。这实际上比这更难,起因很多。一个起因是DOM树往往是不均匀的。这意味着一个核心将比其余核心更多的工作要做。

为了平衡工作,Quantum CSS用了一种称为工作窃取的技术。正在解决DOM节点时,代码将其直接子代并将其分解为1个或者多个“工作单元”。这些工作单位放在队列中。

当一个核心完成了队列中的工作时,它能在其余队列中查找更多的工作。这意味着我们能平均分配工作,而不使用花时间去走树,找出如何提前平衡。

在大多数浏览器中,很难得到这个权利。并行是一个已知的困难问题,CSS引擎非常复杂。它也坐在渲染引擎的另外两个最复杂的部分之间 – DOM和布局。所以很容易引入一个bug,并行性可可以会导致很难追踪的错误,称为数据竞争。我在另一篇文章中更多地解释了这些错误。

假如您接受来自数百或者数千名工程师的贡献,您如何并行编程而不使用担心?这就是我们有Rust的。

用Rust,您能静态地验证您没有数据竞争。这意味着您只要不要让他们进入您的代码,避免辣手的调试错误。编译器不会让你这样做。我将在以后的文章中写下更多关于这一点。在此期间,您能观看关于Rust中的并行性的详情视频,或者者更深入地探讨工作窃取。

有了这个CSS样式计算就会变成一个令人尴尬的并行问题 – 几乎没有什么能让你有效地并行运行它。这意味着我们能接近线性加速。假如您的机器上有4个内核,那么它的运行速度将提高近4倍。

使用规则树加速重新开始

对于每个DOM节点,CSS引擎需要完成所有规则以进行选择器匹配。对于大多数节点,这种匹配可可以不会很频繁地变化。例如,假如使用户将鼠标悬停在父项上,则与之匹配的规则可可以会更改。我们依然需要重新计算其后代的样式来解决属性继承,但是与这些后代匹配的规则可可以不会改变。

假如我们能记下哪些规则与这些后代相匹配,那么这将是很好的,所以我们不必再为它们进行选择器匹配,这就是Firefox以前的CSS引擎借来的规则树。

CSS引擎将通过查找匹配的选择器的过程,而后通过特异性对它们进行排序。从此,它创立了一个链接的规则列表。

该列表将被增加到树中。

CSS引擎尝试将树中的分支数保持在最小。为此,它将尽可可以地重使用一个分支。

假如列表中的大多数选择器与现有分支相同,则它将遵循相同的路径。但是它可可以会到达列表中的下一个规则不在树的这个分支中。只有在这一点上它才会增加一个新的分支。

DOM节点将取得指向最后插入的规则的指针(在本示例中为div#warning规则)。这是最具体的一个。

在restyle上,引擎会快速检查以查看父母的更改能否可可以改变与孩子相匹配的规则。假如没有,则对于任何后代,引擎能跟随后代节点上的指针来取得该规则。从那里,它能将树跟随到根,以取得匹配规则的完整列表,从最具体到最不具体。这意味着它能完全跳过选择器匹配和排序。

因而,这有助于减少重建期间所需的工作。但是,在初始设计时,还是有很多工作。假如您有10,000个节点,您依然需要选择器匹配10,000次。但还有另一种加速方式。

加快样式共享缓存的初始渲染(和级联)

想想一个具备数千个节点的页面。许多节点将匹配相同的规则。例如,想想一个漫长的维基百科页面…主要内容区域中的段落应该完全匹配完全相同的规则,并且具备完全相同的计算样式。

假如没有优化,则CSS引擎必需单独匹配每个段落的选择器和计算样式。但是,假如有一种方式来证实样式将从段落到段落相同,则引擎能只做一次工作,并将每个段落节点指向相同的计算方式。

这就是Safari和Chrome浏览器启发的风格共享缓存。完成解决节点后,将计算的样式放入缓存中。而后,在开始下一个节点的计算样式之前,它会运行少量检查来查看能否能用缓存中的某些内容。

这些支票是:

  • 2节点能否具备相同的ids,类等?假如是这样,那么他们会匹配相同的规则。

  • 对于任何不是基于选择器的内联样式,例如,节点能否具备相同的值?假如是这样,那么上面的规则也不会被覆盖,也不会被同样的覆盖。

  • 父母双方指向相同的计算样式对象吗?假如是这样,那么继承的值也将是一样的。

这些检查一开始就在早期的风格共享缓存中。但是还有很多其余样式可可以不匹配的小案例。例如,假如CSS规则用:first-child选择器,则两个段落可可以不匹配,即便上面的检查表明它们应该是。

在WebKit和Blink中,样式共享缓存将在这些情况下放弃,而不用缓存。随着越来越多的网站用这些现代选择器,优化越来越有使用,所以Blink团队最近删除了它。但事实证实,风格共享缓存有一种方法来跟上这些变化。

在Quantum CSS中,我们收集所有这些奇怪的选择器,并检查它们能否适使用于DOM节点。而后我们将答案存储为1和0。假如两个元素具备相同的一个和零个,我们知道它们绝对匹配。

假如DOM节点能共享已经计算的样式,则能跳过几乎所有的工作。由于页面通常具备多个具备相同样式的DOM节点,所以这种风格共享缓存能节省内存并且还可以够加快速度。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 一个超级快速的CSS引擎:Quantum CSS(又名Stylo)

发表回复