IFC,渲染层与合成层,Hidden_Class,Fiber,Node多进程等

IFC

IFC的行框高度由它包含元素的最高高度来决定。在一个行内格式化上下文中,盒是一个接一个水平放置的,从包含块的顶部开始,同时这些盒之间的水平margin,border和padding都有效。

  1. 创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。
  2. 当inline-level box宽度大于父容器宽度时会被拆分成多个inline-level box,左边距对第一个inline-level box生效,右边距对最后一个inline-level box生效。

渲染层和合成层

首先这两个产生的条件并不一样,如abosolute定位并加上z-index:3的元素与abosolute加z-index:5的元素折叠,这只会生成新的渲染层,自然5在上,3在下。

合成层需要显示和隐式合成,前者诸如我们添加transformZ:0,会显示生成新的合成层,而z-index-5不可能存在于新的合成层下面,所以它也被隐式提升为了新的合成层。

注意BFC也是生成了新的渲染层,这样我们就很好的去理解为什么BFC可以解决同级边距折叠的问题,因为他们根本不再一个层面上。

V8 Hidden Class

首先,JS作为动态类型的语言,对象属性是可以在运行过程中动态的增删改的,若使用类似字典的数据结构来存储对象的属性,相对于静态类型的语言,动态查找属性在内存中的位置要慢的很多,为了提高访问速度,V8使用动态的创建hidden_class的形式去优化。

一个直白的例子:

function fn(){this.a = a;this.b = b}

当我们new fn() 时,首先会创建一个空的hidden_class,称为c0,接着执行到第一条语句时,会在c0的基础上创建c1,c1代替c0成为这个对象新的hidden_class,以此类推,最后c2是这个对象的hidden_class。

动态创建hidden_class的行为看起来很低效,但是当hidden_class可以被反复利用的时候,这种方式看起来就高效多了。

通知这种方式也是有局限性的,如如果我们使用delete方法,对象又会倒退回字典查找模式,删除属性,并进一步优化,代价很大。

hidden_class还有很多知识,这里只是九牛一毛罢了。

几个React常问的问题

首先是事件的bind(this),JSX的语法糖最终会被转化为React.createElement方法,最终所有的事件都会被dispatchEvent分发,在这个过程中,函数会被当作参数传递,this 是很容易丢失的,React处于性能优化的角度,让我们手动加 bind。

Fiber,简单的说是一种单线程时间调度的方法,React递归比较虚拟DOM树并一口气patch到真实DOM上的过程我们可以看作是一个长进程,而Fiber的作用就是中断这个过程,将控制权交回浏览器,让位给高优先级的任务,浏览器空闲后再恢复渲染,这可能也是Fiber(协程)的由来,因为和它的思想有些类似。
具体地说,当浏览器执行完高优先级的任务后,会分出一片时间块给React程序执行,当有更高优先级的任务时,React再将权力返回给浏览器,这里使用了超时检查的机制,如我们常见的16ms。下图是我们常见的1frame内浏览器可以做的事:
在这里插入图片描述
React利用了requestIdleCallback,同时对不支持这个API的浏览器添加了polyfill。在这个空闲时间内,从根节点开始遍历 Fiber Node,并在一段时间后交还给浏览器。

当然,React也为了Fiber架构做出了大量的调整,由于之前同步的、递归的Stack Reconcilation无法随意中断,也很难被恢复,不利于异步处理等特点,React转而使用了链表来模拟栈结构:
在这里插入图片描述
同时现在React的每次渲染都分为了两个阶段,一个是协调,一个是提交,前者可以中断,后者仍然需要一口气执行到底(协调和提交是交替进行的)。

上面分类的讲述了Fiber,下面我们引用这里的文章看一下执行过程:

第一部分从 ReactDOM.render() 方法开始,把接收的 React Element 转换为 Fiber 节点,并为其设置优先级,创建 Update,加入到更新队列,这部分主要是做一些初始数据的准备。

第二部分主要是三个函数:scheduleWork、requestWork、performWork,即安排工作、申请工作、正式工作三部曲,React 16 新增的异步调用的功能则在这部分实现,这部分就是 Schedule 阶段,前面介绍的 Cooperative Scheduling 就是在这个阶段,只有在这个解决获取到可执行的时间片,第三部分才会继续执行。具体是如何调度的,后面文章再介绍,这是 React 调度的关键过程。

第三部分是一个大循环,遍历所有的 Fiber 节点,通过 Diff 算法计算所有更新工作,产出 EffectList 给到 commit 阶段使用,这部分的核心是 beginWork 函数,这部分基本就是 Fiber Reconciler ,包括 reconciliation 和 commit 阶段。

Fiber带来的影响是很大的,包括最新DOM算法的改变,可以见这篇文章,不说了,我去学了。

node多进程

进程与线程的区别,前者是系统调度运行的基本单位,后者是CPU调度运行的基本单位,前者是后者的容器。

Node开启多进程不是为了解决高并发,主要是解决了单进程模式下 Node.js CPU 利用率不足的情况,充分利用多核 CPU 的性能。

Nodejs创建多进程的方式主要有cluster和child_process两种方式。两者都是以fork一系列的API为主开辟新的进程,后者更加灵活,前者通过需要通过一个主进程管理多个工作进程,通过循环算法实现负载均衡,能够更简单的提高多核的利用率。

创建多进程并不是终点,能够实现进程间的通信,即IPC才是真正能够提升效率的表现,Node中实现IPC通道是依赖于libuv的,父进程在实际创建子进程之前,会创建IPC通道并监听它,然后才真正的创建出子进程。

想深入了解,还是看这篇文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章