本文翻译自Inside a super fast CSS engine: Quantum CSS ,若是想要阅读原文,能够点击前往,如下内容夹杂本人一些思考,翻译也并不必定彻底。css
为何翻译这篇文章尼,一开始只是好奇,基本在前端技术圈子混过都知道火狐正在用Rust语言开发新的浏览器引擎,做为前端开发对火狐的感情仍是大大的有(虽然如今已经离不开chrome了),可是仍是但愿火狐可以再次引领Web的变革。
能够说前端这几年解决了前端工程化的不少痛点,可是性能这个坎依旧,指望webassembly尽快普及,可是对于前端一定又是一场腥风血雨,前端不会一直是如今这样的前端。既然webassembly出现了,那css怎么办,目前并没据说出现什么新的技术替代它(虽然它真的已经很不适合现代的前端了),那么只能开发一个新的引擎提升性能,这就是火狐家的量子引擎:Quantum CSS(又叫Stylo)。前端
这是火狐正在开发的Quantum项目,目的固然是为了让浏览器更快,从上图能够看获得各个模块,而Quantum CSS处于中间位置,这跟它在整个渲染过程当中的位置同样,利用Rust能够至关有效利用现代处理器多核心的特性,可以几倍的提速。既然这么厉害,那从哪里能够体验尼:在火狐Nightly版进入about:config设置layout.css.servo.enabled 属性为 true就能够体验这吊炸天的引擎。web
站在巨人的肩膀上,固然除了利用现代处理器的并行能力,还借鉴当前各家浏览器积累的一些优化技术,接下来会一一解析这些优化技术,如何让引擎更快。chrome
CSS引擎是浏览器渲染引擎的一部分,而渲染引擎会把咱们的HTML和CSS转换成屏幕上的像素(也就是画面吧)。
各家浏览器都会有自家的渲染引擎,例如谷歌的Blink,Edge的EdgeHTML,Safari的Webkit和火狐的Gecko,虽然有这么多引擎,可是他们都作着一样的事情:把HTML和CSS渲染成咱们能够感知的界面。
而他们内部的工做须要:前端工程化
综合后,咱们能够知道CSS引擎开始计算样式时须要两样东西:DOM的节点树和一系列的样式规则。
CSS引擎会遍历全部DOM节点并计算每一个节点所应用的样式,它会让DOM节点每一个CSS属性都有一个值,就算你在样式表中并无声明,它可能来自继承或者默认值,或者客户端的样式表(User Agent Style)。
能够认为引擎就像填表格同样,把这些最后计算出来的值一个一个填进去。浏览器
为了获得上面的表格,CSS引擎须要作两件事:ide
首先找出配置当前的节点的样式规则,放到一个list上去,这里也包括客户端的样式表。布局
而后会计算各个样式规则之间的权重,而且根据权重排序。性能
根据权重大小,得出最终应用的样式属性的值。学习
级联(The cascade)目的是为了让CSS更容易编写和维护,因为级联的存在,你能够在body上设置color属性,而li,p,span等元素能够直接使用一样的color,不须要每一个元素都要去定义一次。
为了实现这个功能,CSS引擎会从表格里面寻找一些属性值仍然为空的值,若是属性默认是继承的话,CSS引擎会从父节点那里继承属性值,若是全部父节点都没有定义该属性值的话,就会使用默认的值。
如今咱们的表格都填满了
上述表格的形式,只是一种表现方式,引擎真实的内部不是这样的。CSS拥有成千上百的属性,若是引擎为每一个节点都生成这样一张表,会很快耗掉全部内存。
相反引擎内部一般会使用style struct sharing,样式的数据会集中在不一样对象里面(style struct),而后使用指针指向这些对象。
这会很大程度上节省内存,由于各个节点间都颇有可能拥有类似的属性值(例如兄弟节点间),另外由于不少属性也是经过继承获取的,因此父节点能够跟子节点间共享这些属性值。
若是咱们不去优化这些工做,整个样式计算工做就会是这样:
这是巨量的工做,并且并不只仅在页面加载的时候发生,它会随着用户的交互时刻都在存在(例如hover一个元素,CSS引擎须要重新计算样式)。
这样就意味着必须得去优化样式的计算工做,在过去20年,已经测试过不一样的优化策略,而Quantum CSS则是组合利用这些最优的优化策略。
咱们如今的CPU大多拥有多个核心,而Quantum CSS则会把不一样DOM节点的样式计算工做分配到不一样的核心上去,可是实现也有至关的难度,其中一个缘由就是DOM节点树并不必定均匀的,这会致使其中一部分核心工做负荷比其余核心大。
为了让各个核心工做负荷更加合理,Quantum CSS使用了一种技术称做 work stealing,当一个DOM节点被处理的时候,引擎能够把它的子节点计算工做分红几个“work units”而且放进队列中。
当其中一个核心清空自身队列的工做后,它可以寻找其余队列上的其余work units而后执行,这意味着咱们不须要提早就去分配好工做,在运行时也会达到最高的工做效率。
在大部分浏览器里面,很难让这种机制毫无错误的运行,并且CSS引擎自己就很是复杂,它在渲染引擎中两个最复杂的模块(DOM和layout)中间。这个过程很是容易产生bug,并且并行程序致使的bug很是难debug,能够经过这篇文章了解更多。
对于每一个DOM节点,CSS引擎须要遍历全部样式规则去进行selector matching,且对于大部分节点这种matching并不会常常改变。例如,用户hover一个父节点,它的样式规则可能会改变,可是咱们仍然须要从新子节点的样式规则去处理属继承的属性值,而子节点以前匹配的规则颇有可能不会改变。
若是咱们记录好子节点匹配哪些样式规则,而不用每次都进行一次selector matching,这可能会获得很大的优化。这就是所谓的rule tree,火狐前一个引擎所作的那样。
CSS引擎会遍历样式规则帮DOM节点找出匹配的选择器,而后根据权重排序,从而建立出一个样式规则的链表,而后将这个链表添加到rule tree中。
CSS引擎会尽量利用已有的分支,为rule tree保持最少的分支数。
若是大部分链表中大部分的选择器,跟已存在的分支同样,引擎会顺着路径,除非它到达一个节点,rule tree并不存在同样分支,引擎就会添加一个新的分支。
在从新计算样式的过程当中,引擎会快速检查父节点的改变是否会致使子节点匹配的样式规则改变。若是没有,子节点能够根据本身指向rule tree节点的指针计算样式。引擎会rule tree的节点往上查找,获取整个匹配的规则,从权重最大到权重最小的。这样就能够很轻松的跳过selector matching这一步了。
可是这样仍然还有不少工做要作,毕竟一个页面上节点成千上万,这时候并行计算的魔法又能够大显神威了。
因为整个页面的节点可能会有成千上万个,它们当中不少都匹配着相同的规则。例如wiki页面中每一个p元素其实逗匹配着相同的样式规则,拥有同样的computed styles。
若是这里没有作优化,可能每一个段落都要从新计算,可是若是有一种方法来证实每一个段落的样式规则都是同样,引擎就只需计算一次就能够了。
这就是所谓的style sharing cache,由Chrome和Safari所发明的一种优化方式,在引擎处理一个节点后会把computed style放到cache里面,而后开始计算下一个节点的时候,引擎会先检查cache里面是否已经存在计算后的值。
而这些检查包括:
可是也有不少其余的状况,致使这些检查失效,例如:若是一个CSS规则使用了:first-child选择器,就算两个节点都已经符合上述的规则,结果也会是检查不经过。
在Webkit和Blink, style sharing cache在这些状况下会放弃检查并不会使用cache。因为大部分网站都使用了这些modern selectors(CSS3),这个优化的做用变得愈来愈少,因此Blink团队最近把它移除了。
在Quantum CSS,咱们收集了全部这些怪异的选择器(CSS3)而后让它们加入检查。咱们会把结果存储为0和1,若是两个元素拥有一样的0和1,那咱们就知道他们是匹配一样的样式规则。
这样咱们就能够继续享受style sharing cache带来的优化。
前半部分可让咱们知道CSS引擎的工做内容,后半部分让咱们了解新引擎是如何优化性能的,真的学习了不少,我想你也同样。