将来以此为依据来介绍重绘和回流,以及让更新视图的另外一种方式——合成。
首先介绍回流。回流也叫重排。
触发条件
简单来说,就是当我们对 DOM 结构的修改引发 DOM 几何尺寸变化的时候,会发生回流的过程。
具体一点,有以下的操作会触发回流:
1.一个 DOM 元素的几何属性变化,常见的几何属性有width、height、padding、margin、left、top、border 等等, 这个很好理解。
2.使 DOM 节点发生增减或者移动。
3.读写 offset、scroll和client属性的时候,浏览器为了获取这些值,需要进行回流操作。
4.调用 window.getComputedStyle 方法。
回流过程
依照上面的渲染流水线,触发回流的时候,如果 DOM 结构发生改变,则重新渲染 DOM 树,然后将后面的流程(包括主线程之外的任务)全部走一遍。
相当于将解析和合成的过程重新又走了一篇,开销是非常大的。
触发条件
当 DOM 的修改导致了样式的变化,并且没有影响几何属性的时候,会导致重绘(repaint)。
重绘过程
由于没有导致 DOM 几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程。流程如下:
跳过了生成布局树和建图层树的阶段,直接生成绘制列表,然后继续进行分块、生成位图等后面一系列操作。
可以看到,重绘不一定导致回流,但回流一定发生了重绘。
还有一种情况,是直接合成。比如利用 CSS3 的transform、opacity、filter这些属性就可以实现合成的效果,也就是大家常说的GPU加速。
在合成的情况下,会直接跳过布局和绘制流程,直接进入非主线程处理的部分,即直接交给合成线程处理。交给它处理有两大好处:
- 能够充分发挥GPU的优势。合成线程生成位图的过程中会调用线程池,并在其中使用GPU进行加速生成,而GPU 是擅长处理位图数据的。
2.没有占用主线程的资源,即使主线程卡住了,效果依然能够流畅地展示。
知道上面的原理之后,对于开发过程有什么指导意义呢?
避免频繁使用 style,而是采用修改class的方式。
使用createDocumentFragment进行批量的 DOM 操作。
对于 resize、scroll 等进行防抖/节流处理。
添加 will-change: tranform ,让渲染引擎为其单独实现一个图层,当这些变换发生时,仅仅只是利用合成线程去处理这些变换,而不牵扯到主线程,大大提高渲染效率。当然这个变化不限于tranform, 任何可以实现合成效果的 CSS 属性都能用will-change来声明。
谈到HTTPS, 就不得不谈到与之相对的HTTP。HTTP的特性是明文传输,因此在传输的每一个环节,数据都有可能被第三方窃取或者篡改,具体来说,HTTP 数据经过 TCP 层,然后经过WIFI路由器、运营商和目标服务器,这些环节中都可能被中间人拿到数据并进行篡改,也就是我们常说的中间人攻击。
为了防范这样一类攻击,我们不得已要引入新的加密方案,即 HTTPS。
HTTPS并不是一个新的协议, 而是一个加强版的HTTP。其原理是在HTTP和TCP之间建立了一个中间层,当HTTP和TCP通信时并不是像以前那样直接通信,直接经过了一个中间层进行加密,将加密后的数据包传给TCP, 响应的,TCP必须将数据包解密,才能传给上面的HTTP。这个中间层也叫安全层。安全层的核心就是对数据加解密。
接下来我们就来剖析一下HTTPS的加解密是如何实现的。
首先需要理解对称加密和非对称加密的概念,然后讨论两者应用后的效果如何。
对称加密是最简单的方式,指的是加密和解密用的是同样的密钥。
而对于非对称加密,如果有 A、 B 两把密钥,如果用 A 加密过的数据包只能用 B 解密,反之,如果用 B 加密过的数据包只能用 A 解密。
接着我们来谈谈浏览器和服务器进行协商加解密的过程。
首先,浏览器会给服务器发送一个随机数client_random和一个加密的方法列表。
服务器接收后给浏览器返回另一个随机数server_random和加密方法。
现在,两者拥有三样相同的凭证: client_random、server_random和加密方法。
接着用这个加密方法将两个随机数混合起来生成密钥,这个密钥就是浏览器和服务端通信的暗号。
如果用对称加密的方式,那么第三方可以在中间获取到client_random、server_random和加密方法,由于这个加密方法同时可以解密,所以中间人可以成功对暗号进行解密,拿到数据,很容易就将这种加密方式破解了。
既然对称加密这么不堪一击,我们就来试一试非对称加密。在这种加密方式中,服务器手里有两把钥匙,一把是公钥,也就是说每个人都能拿到,是公开的,另一把是私钥,这把私钥只有服务器自己知道。
好,现在开始传输。
浏览器把client_random和加密方法列表传过来,服务器接收到,把server_random、加密方法和公钥传给浏览器。
现在两者拥有相同的client_random、server_random和加密方法。然后浏览器用公钥将client_random和server_random加密,生成与服务器通信的暗号。
这时候由于是非对称加密,公钥加密过的数据只能用私钥解密,因此中间人就算拿到浏览器传来的数据,由于他没有私钥,照样无法解密,保证了数据的安全性。
这难道一定就安全吗?聪明的小伙伴早就发现了端倪。回到非对称加密的定义,公钥加密的数据可以用私钥解密,那私钥加密的数据也可以用公钥解密呀!
服务器的数据只能用私钥进行加密(因为如果它用公钥那么浏览器也没法解密啦),中间人一旦拿到公钥,那么就可以对服务端传来的数据进行解密了,就这样又被破解了。而且,只是采用非对称加密,对于服务器性能的消耗也是相当巨大的,因此我们暂且不采用这种方案。
可以发现,对称加密和非对称加密,单独应用任何一个,都会存在安全隐患。那我们能不能把两者结合,进一步保证安全呢?
其实是可以的,演示一下整个流程:
浏览器向服务器发送client_random和加密方法列表。
服务器接收到,返回server_random、加密方法以及公钥。
浏览器接收,接着生成另一个随机数pre_random, 并且用公钥加密,传给服务器。(敲黑板!重点操作!)
服务器用私钥解密这个被加密后的pre_random。
现在浏览器和服务器有三样相同的凭证:client_random、server_random和pre_random。然后两者用相同的加密方法混合这三个随机数,生成最终的密钥。
然后浏览器和服务器尽管用一样的密钥进行通信,即使用对称加密。
这个最终的密钥是很难被中间人拿到的,为什么呢? 因为中间人没有私钥,从而拿不到pre_random,也就无法生成最终的密钥了。
回头比较一下和单纯的使用非对称加密, 这种方式做了什么改进呢?本质上是防止了私钥加密的数据外传。单独使用非对称加密,最大的漏洞在于服务器传数据给浏览器只能用私钥加密,这是危险产生的根源。利用对称和非对称加密结合的方式,就防止了这一点,从而保证了安全。
尽管通过两者加密方式的结合,能够很好地实现加密传输,但实际上还是存在一些问题。黑客如果采用 DNS 劫持,将目标地址替换成黑客服务器的地址,然后黑客自己造一份公钥和私钥,照样能进行数据传输。而对于浏览器用户而言,他是不知道自己正在访问一个危险的服务器的。
事实上HTTPS在上述结合对称和非对称加密的基础上,又添加了数字证书认证的步骤。其目的就是让服务器证明自己的身份。
为了获取这个证书,服务器运营者需要向第三方认证机构获取授权,这个第三方机构也叫CA(Certificate Authority), 认证通过后 CA 会给服务器颁发数字证书。
这个数字证书有两个作用:
服务器向浏览器证明自己的身份。
把公钥传给浏览器。
这个验证的过程发生在什么时候呢?
当服务器传送server_random、加密方法的时候,顺便会带上数字证书(包含了公钥), 接着浏览器接收之后就会开始验证数字证书。如果验证通过,那么后面的过程照常进行,否则拒绝执行。
现在我们来梳理一下HTTPS最终的加解密过程:
浏览器拿到数字证书后,如何来对证书进行认证呢?
首先,会读取证书中的明文内容。CA 进行数字证书的签名时会保存一个 Hash 函数,来这个函数来计算明文内容得到信息A,然后用公钥解密明文内容得到信息B,两份信息做比对,一致则表示认证合法。
当然有时候对于浏览器而言,它不知道哪些 CA 是值得信任的,因此会继续查找 CA 的上级 CA,以同样的信息比对方式验证上级 CA 的合法性。一般根级的 CA 会内置在操作系统当中,当然如果向上找没有找到根级的 CA,那么将被视为不合法。
HTTPS并不是一个新的协议, 它在HTTP和TCP的传输中建立了一个安全层,
利用对称加密和非对称加密结合数字证书认证的方式,让传输过程的安全性大大提高。