开始

本文翻译自Inside a super fast CSS engine: Quantum CSS,如果想要阅读原文,可以点击前往,以下内容夹杂本人一些思考,翻译也并不一定完全。

碎碎念

为什么翻译这篇文章尼,一开始只是好奇,基本在前端技术圈子混过都知道火狐正在用Rust语言开发新的浏览器引擎,作为前端开发对火狐的感情还是大大的有(虽然现在已经离不开chrome了),但是还是希望火狐能够再次引领Web的变革。
可以说前端这几年解决了前端工程化的很多痛点,但是性能这个坎依旧,期望webassembly尽快普及,但是对于前端必定又是一场腥风血雨,前端不会一直是现在这样的前端。既然webassembly出现了,那css怎么办,目前并没听说出现什么新的技术替代它(虽然它真的已经很不适合现代的前端了),那么只能开发一个新的引擎提高性能,这就是火狐家的量子引擎:Quantum CSS(又叫Stylo)。

加速器

这是火狐正在开发的Quantum项目,目的当然是为了让浏览器更快,从上图可以看得到各个模块,而Quantum CSS处于中间位置,这跟它在整个渲染过程中的位置一样,利用Rust可以相当有效利用现代处理器多核心的特性,能够几倍的提速。既然这么厉害,那从哪里可以体验尼:在火狐Nightly版进入about:config设置layout.css.servo.enabled 属性为 true就可以体验这吊炸天的引擎。

站在巨人的肩膀上,当然除了利用现代处理器的并行能力,还借鉴当前各家浏览器积累的一些优化技术,接下来会一一解析这些优化技术,如何让引擎更快。

CSS引擎会干些啥工作

CSS引擎是浏览器渲染引擎的一部分,而渲染引擎会把我们的HTML和CSS转换成屏幕上的像素(也就是画面吧)。
各家浏览器都会有自家的渲染引擎,例如谷歌的Blink,Edge的EdgeHTML,Safari的Webkit和火狐的Gecko,虽然有这么多引擎,但是他们都做着同样的事情:把HTML和CSS渲染成我们可以感知的界面。
而他们内部的工作需要:

  • 首先解析HTML文档,生成DOM节点树,让浏览器可以知道页面的结构和各个节点的关系。
  • 然后就要弄清楚每个元素长什么样子了,圆的还是方的,有边框还是没边框等等;所以这个时候就需要知道每个元素需要应该用什么样式。
  • 除了知道长的样子,还要知道各个节点的位置和布局。引擎会为所有可见的节点都会创建一个box,但是box并不仅为DOM节点而创建,DOM节点内部也可以有其他box,例如几行文字。
  • 知道该应用的样式和位置,现在轮到绘制这些box了,这个工作可能会在多个layer上发生。可以认为就像旧时动画制作技术,在一张透明的胶片上绘制背景,在另外的胶片上绘制人物或者其他元素。这样的话就如果人物会动起来的时候,就只用重新绘制人物那张胶片了,不用绘制其他的,这样就省事好多了。
  • 到了这一步现在我们有不同的胶片(layer),是时候开始合成了(composite),但是合成之前,我们可能还会应用一些transform,旋转啊,偏移啊等等。最后把他们按照层级堆在一起,背景在后,人物在前等等,然后最终渲染到屏幕上。

综合后,我们可以知道CSS引擎开始计算样式时需要两样东西:DOM的节点树和一系列的样式规则。
CSS引擎会遍历所有DOM节点并计算每个节点所应用的样式,它会让DOM节点每个CSS属性都有一个值,就算你在样式表中并没有声明,它可能来自继承或者默认值,或者客户端的样式表(User Agent Style)。
可以认为引擎就像填表格一样,把这些最后计算出来的值一个一个填进去。

为了得到上面的表格,CSS引擎需要做两件事:

  • 搞清楚每个节点所应用的样式规则(selector matching)
  • 把一些你没有声明的值,根据继承或者默认值补充上去(the cascade)

Selector matching

首先找出配置当前的节点的样式规则,放到一个list上去,这里也包括客户端的样式表。

然后会计算各个样式规则之间的权重,并且根据权重排序。

根据权重大小,得出最终应用的样式属性的值。

The cascade

级联(The cascade)目的是为了让CSS更容易编写和维护,由于级联的存在,你可以在body上设置color属性,而li,p,span等元素可以直接使用同样的color,不需要每个元素都要去定义一次。
为了实现这个功能,CSS引擎会从表格里面寻找一些属性值仍然为空的值,如果属性默认是继承的话,CSS引擎会从父节点那里继承属性值,如果所有父节点都没有定义该属性值的话,就会使用默认的值。
现在我们的表格都填满了

style struct sharing

上述表格的形式,只是一种表现方式,引擎真实的内部不是这样的。CSS拥有成千上百的属性,如果引擎为每个节点都生成这样一张表,会很快耗掉所有内存。
相反引擎内部通常会使用style struct sharing,样式的数据会集中在不同对象里面(style struct),然后使用指针指向这些对象。

这会很大程度上节省内存,因为各个节点间都很有可能拥有相似的属性值(例如兄弟节点间),另外因为很多属性也是通过继承获取的,所以父节点可以跟子节点间共享这些属性值。

如何让这些工作更快

如果我们不去优化这些工作,整个样式计算工作就会是这样:

这是巨量的工作,而且并不仅仅在页面加载的时候发生,它会随着用户的交互时刻都在存在(例如hover一个元素,CSS引擎需要从新计算样式)。

这样就意味着必须得去优化样式的计算工作,在过去20年,已经测试过不同的优化策略,而Quantum CSS则是组合利用这些最优的优化策略。

Run it all in parallel

我们现在的CPU大多拥有多个核心,而Quantum CSS则会把不同DOM节点的样式计算工作分配到不同的核心上去,但是实现也有相当的难度,其中一个原因就是DOM节点树并不一定均匀的,这会导致其中一部分核心工作负荷比其他核心大。

为了让各个核心工作负荷更加合理,Quantum CSS使用了一种技术称作 work stealing,当一个DOM节点被处理的时候,引擎可以把它的子节点计算工作分成几个“work units”并且放进队列中。
当其中一个核心清空自身队列的工作后,它能够寻找其他队列上的其他work units然后执行,这意味着我们不需要提前就去分配好工作,在运行时也会达到最高的工作效率。

在大部分浏览器里面,很难让这种机制毫无错误的运行,而且CSS引擎本身就非常复杂,它在渲染引擎中两个最复杂的模块(DOM和layout)中间。这个过程非常容易产生bug,而且并行程序导致的bug非常难debug,可以通过这篇文章了解更多

Speed up restyles with the Rule Tree

对于每个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这一步了。

但是这样仍然还有很多工作要做,毕竟一个页面上节点成千上万,这时候并行计算的魔法又可以大显神威了。

Speed up initial render (and the cascade) with the style sharing cache

由于整个页面的节点可能会有成千上万个,它们当中很多都匹配着相同的规则。例如wiki页面中每个p元素其实逗匹配着相同的样式规则,拥有一样的computed styles。
如果这里没有做优化,可能每个段落都要重新计算,但是如果有一种方法来证明每个段落的样式规则都是一样,引擎就只需计算一次就可以了。
这就是所谓的style sharing cache,由Chrome和Safari所发明的一种优化方式,在引擎处理一个节点后会把computed style放到cache里面,然后开始计算下一个节点的时候,引擎会先检查cache里面是否已经存在计算后的值。
而这些检查包括:

  • 两个节点是否都有一样的ID和Class等,如果一样它们匹配同样的规则。
  • 对于非selector的行内样式,它们是否拥有一样的值。
  • 它们的父节点都是否指向同一个computed style object,如果一样它们的继承的值都会一样。

但是也有很多其他的情况,导致这些检查失效,例如:如果一个CSS规则使用了:first-child选择器,就算两个节点都已经符合上述的规则,结果也会是检查不通过。
在Webkit和Blink, style sharing cache在这些情况下会放弃检查并不会使用cache。由于大部分网站都使用了这些modern selectors(CSS3),这个优化的作用变得越来越少,所以Blink团队最近把它移除了。
在Quantum CSS,我们收集了所有这些怪异的选择器(CSS3)然后让它们加入检查。我们会把结果存储为0和1,如果两个元素拥有同样的0和1,那我们就知道他们是匹配同样的样式规则。

这样我们就可以继续享受style sharing cache带来的优化。

结束

前半部分可以让我们知道CSS引擎的工作内容,后半部分让我们了解新引擎是如何优化性能的,真的学习了很多,我想你也一样。

Quantum CSS,一个超快的CSS引擎的更多相关文章

  1. CSS Hack汇总快查(CSS兼容代码演示)

    文章出处和来源网址:http://www.divcss5.com/css-hack/c284.shtml 以下是常用CSS HACK问题及解决代码-DIV+CSS网支持 1.屏蔽IE浏览器(也就是IE ...

  2. min.css----全世界最快的CSS框架

      有一个CSS框架,叫min.css,它号称是全世界最快的. 难怪,它的代码就这一点. 你看它的页面例子,像Bootstrap,但比后者轻多了,它只是一些CSS样式,没有JavaScript代码. ...

  3. PixiJS - 基于 WebGL 的超快 HTML5 2D 渲染引擎

    Pixi.js 是一个开源的HTML5 2D 渲染引擎,使用 WebGL 实现,不支持的浏览器会自动降低到 Canvas 实现.PixiJS 的目标是提供一个快速且轻量级的2D库,并能兼容所有设备.此 ...

  4. 10个超漂亮的CSS 3D特效

    10个超漂亮的CSS 3D特效 一.总结 一句话总结: 后面有空得好好练一练,也可以作为录课素材 二.10个超漂亮的CSS 3D特效 转自或参考:10个超漂亮的CSS 3D特效https://blog ...

  5. 一个可以自动生成css样式的插件happycss

    一直在页面写css, 重复写着样式,发现布局中,特别是h5,大量的样式都是margin,padding,width,height, 而,当我们需要给一个标签写样式的时候,避免内联样式,我们又需要取cl ...

  6. kube框架结构-一个小型响应式CSS框架

    当你开始初建一个新的项目时,你可能需要一个不太复杂的基础框架,Kube框架应该是你最好的选择.一个独立的CSS文件,帮助你更简单的创建响应式的的布局设计. Kube Framework包括网格.按钮. ...

  7. CSS画一个三角形,CSS绘制空心三角形,CSS实现箭头

     壹 ❀ 引 这两天因为项目工作较少,闲下来去看了GitHub上关于面试题日更收录的文章,毕竟明年有新的打算.在CSS收录中有一题是 用css创建一个三角形,并简述原理 .当然对于我来说画一个三角形是 ...

  8. 纯CSS一个div实现无缝隙尖角框

    话不多说直接先上效果图 其实原理很简单,就是一个带边框的方块加上一个黑色三角形和一个白色三角形,最后通过position定位实现. 代码如下: HTML就一个div <div></d ...

  9. 搭建一个超好用的 cmdb 系统

    10 分钟为你搭建一个超好用的 cmdb 系统 CMDB 是什么,作为 IT 工程师的你想必已经听说过了,或者已经烂熟了,容我再介绍一下,以防有读者还不知道.CMDB 的全称是 Configurati ...

随机推荐

  1. pygame写俄罗斯方块

    代码搬运修改自python编写俄罗斯方块 更新时间:2020年03月13日 09:39:17 作者:勤勉之 from tkinter import * from random import * imp ...

  2. laravel7 权限菜单设置简易升缩

    1:数据库填写数据,pid=0为顶级菜单,pid=对应的id为顶级菜单的子菜单 2:laravel7 创建模型并链接对应的表名 <?php namespace App\models; use I ...

  3. 微信退款通知,退款回调数据解密.SHA256签名AEAD_AES_256_GCM解密

    $xmlResult = file_get_contents("php://input");//获取微信的数据$result = $this->xmlToArray($xml ...

  4. 实践2:如何使用word2vec和k-means聚类寻找相似的城市

    理解业务 一个需求:把相似的目的地整理出来,然后可以通过这些相似目的地做相关推荐,或者是相关目的地的推荐 准备数据 Word2Vec算法:可以学习输入的文本,并输出一个词向量模型 对数据进行清洗,去出 ...

  5. angular1使用echarts2绘制图标

    一.绘制柱状图:直接上代码 1.首先下载echarts-all文件(这里就不赘述了),然后是创建一个bar.js及内容如下: bar.js内容: var app = require("../ ...

  6. LGP5142题解

    题意简明,不说了( 因为教练让同学们做线段树的题,早就会了线段树的我就来爆踩水水蓝了/kk 首先推一下柿子: \[\frac 1 n\sum_{i=1}^n(a_i^2-2 \times a_i \t ...

  7. Spring——自动装配的三种实现方式

    依赖注入的本质是装配,装配是依赖注入的具体行为 spring会在上下文中自动寻找,并自动给bean装配属性 自动装配的三种方式 (1).在xml中显式的装配 (2).在java中显式的装配 (3).隐 ...

  8. oracle 如何在表中有数据的情况下,修改表字段的类型或者增加表字段的长度

    场景:项目中某张表的字段长度不够用了,现在要增加其长度 分两种情况: 1.表中没有数据的情况,直接一条sql语句就能解决 alter     table    表名    modify(字段名   字 ...

  9. 5月2日 python学习总结 IO模型

    IO模型 1.阻塞IO 2.非阻塞IO 3.多路复用IO 4.异步IO 一.阻塞IO blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了. 实际上,除非 ...

  10. 《浅谈产品》——加油APP的平台是如何做的

    最近油价又上涨了,我们平常去加油站加油用到"某滴加油"."某团加油"这些APP,一般情况下加200的油,各种优惠下来,最终只需要付170左右就可以了,基本是优惠 ...