Fiber详解
为什么会出现Fiber
React V15在渲染的时候, React 会从根部递归比对VirtualDOM树,找出需要变动的节点,然后同步更新它们, 这个过程 React 称为 Reconcilation(中文可以译为协调) 。React15及之前协调是不可以被中断的,随着项目越来越复杂,层级越来越深,导致更新的时间越来越长,给前端交互上的体验就是卡顿。
Reactv16 为了解决卡顿问题引入了 fiber,React 通过Fiber 架构,让自己的Reconcilation 过程变成可被中断,'适时'地让出CPU执行权。 每一个 fiber 都可以作为一个执行单元来处理,所以每一个 fiber 可以根据自身的过期时间,来判断是否还有空间时间执行更新,如果没有时间更新,就要把主动权交给浏览器去渲染,做一些动画,重排( reflow ),重绘 repaints 之类的事情,这样就能给用户感觉不是很卡。然后等浏览器空余时间,在通过 scheduler (调度器),再次恢复执行单元上来,这样就能本质上中断了渲染,提高了用户体验。
Fiber架构是如何解决卡顿的问题
引入新的数据结构
1.为什么之前的递归比对不能被中断?
因为之前的递归是基于函数’调用栈‘的,因此通常也称它为Stack Reconcilation
。依赖于调用栈的方式不能随意中断、也很难被恢复, 不利于异步处理。 这种调用栈,不是程序所能控制的, 如果你要恢复递归现场,可能需要从头开始, 恢复到之前的调用栈。
2.Fiber的数据结构是怎么样的
export type Fiber = {
// Fiber 类型信息
type: any,
// ...
// ⚛️ 链表结构
// 指向父节点,或者render该节点的组件
return: Fiber | null,
// 指向第一个子节点
child: Fiber | null,
// 指向下一个兄弟节点
sibling: Fiber | null,
}
使用了链表结构,即使处理流程被中断了,我们随时可以从上次未处理完的Fiber继续遍历下去
优先级调度算法
Fiber可以将组件树分解成小的任务单元,并通过一个优先级算法调度这些任务的执行顺序,使得React可以更加高效地渲染组件树,并且可以在不同的渲染阶段中暂停、中断和恢复渲染任务。另外,Fiber还允许React在渲染时对任务的优先级进行动态调整,以更好地响应用户交互、网络请求等外部事件,从而提高应用程序的性能和用户体验。
Fiber是如何做到流程可中断,暂定和恢复的
Fiber可以被看作是一种轻量级的、可中断的执行单元,每个Fiber节点表示一个组件的渲染任务,包含了该组件的状态、属性、子节点等信息。
在React Fiber中,渲染任务被分为多个优先级,React会根据优先级算法来调度这些任务的执行顺序。如果一个任务的优先级较低,那么React可以中断该任务的执行,并暂停渲染过程,转而执行其他优先级较高的任务。这个过程被称为“协调中断”。
当优先级较高的任务完成之后,React会再次调度之前被中断的任务,并从中断的地方恢复渲染过程。这个过程被称为“协调恢复”。在恢复渲染过程时,React会利用之前保存的Fiber节点信息,从而避免重新计算组件状态和属性,从而提高渲染效率。
除了支持中断、暂停和恢复操作外,React Fiber还支持“异步渲染”机制,可以将渲染任务分解为多个较小的子任务,从而提高渲染效率和用户体验。异步渲染可以使得React能够在多个帧之间分配任务,从而避免长时间阻塞主线程,保证页面的流畅性。
React为什么会引入异步调度
React之所以引入异步调度,主要是为了提高应用的性能和用户体验。在传统的React应用中,每次更新状态都会立即重新渲染整个应用,这会导致大量的计算和DOM操作,降低了应用的性能和用户体验。
通过使用异步调度,React可以将渲染任务分解为多个较小的子任务,从而避免长时间阻塞主线程,保证页面的流畅性。具体来说,React通过以下方式实现异步调度:
1.将渲染任务分解为多个优先级较低的子任务:React将渲染任务分解为多个优先级较低的子任务,从而使得每个子任务的计算量和DOM操作量都比较小,避免了长时间的阻塞主线程。
2.利用浏览器的requestIdleCallback API:React利用浏览器的requestIdleCallback API,将渲染任务插入到浏览器的空闲时间段中执行,从而避免长时间阻塞主线程。
3.利用时间切片技术:React还可以利用时间切片技术,将渲染任务分配到多个帧之间执行,从而避免一次性执行大量计算和DOM操作,保证页面的流畅性。
通过引入异步调度,React可以在多个帧之间分配任务,从而避免长时间阻塞主线程,提高应用的性能和用户体验。同时,异步调度还可以提高应用的可维护性,使得开发人员可以更加灵活地控制渲染的过程。
react异步调度原理
React异步调度的实现原理可以分为两部分:任务优先级调度和任务分片。
任务优先级调度 React利用任务优先级调度机制,将渲染任务分解为多个优先级较低的子任务。React内部维护了一个任务队列,每个任务都有一个优先级,高优先级的任务会先执行,低优先级的任务会后执行。React根据任务的优先级和任务队列的长度,动态调整任务的执行顺序,从而保证高优先级任务的及时响应。
1.任务优先级调度机制的实现方式有两种:
基于时间切片的任务优先级调度:React将每个帧分为多个时间片,将任务按照优先级分配到不同的时间片中执行,从而避免一次性执行大量计算和DOM操作,保证页面的流畅性。
基于requestIdleCallback的任务优先级调度:React利用浏览器提供的requestIdleCallback API,将任务插入到浏览器的空闲时间段中执行,从而避免长时间阻塞主线程,保证页面的流畅性。
任务分片 React利用任务分片机制,将渲染任务分解为多个较小的子任务。每个子任务都是短时间内可以完成的任务,执行完一个子任务后,React会根据当前的任务队列和剩余时间,决定是否继续执行下一个子任务,或者将任务延迟到下一个帧中执行。
2.任务分片机制的实现方式有两种:
基于时间切片的任务分片:React将每个帧分为多个时间片,将渲染任务分解为多个较小的子任务,并将子任务按照优先级分配到不同的时间片中执行,从而避免一次性执行大量计算和DOM操作,保证页面的流畅性。
基于requestIdleCallback的任务分片:React利用浏览器提供的requestIdleCallback API,将渲染任务分解为多个较小的子任务,并将子任务插入到浏览器的空闲时间段中执行,从而避免长时间阻塞主线程,保证页面的流畅性。
总之,React利用任务优先级调度和任务分片两种机制,实现了异步调度的功能,从而提高了应用的性能和用户体验。
react的render阶段和commit阶段分别做了哪些事情
React中的渲染过程可以分为两个阶段:render阶段和commit阶段。这两个阶段分别完成不同的任务。
Render阶段
Render阶段是React的第一个阶段,其主要任务是构建Fiber树和更新组件状态。在这个阶段,React会遍历整个组件树,生成Fiber节点,并且计算出每个Fiber节点的状态和属性。在这个阶段,React会执行以下操作:
1.生成Fiber节点:在这个阶段,React会为每个组件生成对应的Fiber节点,并且建立Fiber节点之间的父子关系。
2.计算组件状态和属性:在这个阶段,React会根据组件的状态和属性计算出组件的新状态和属性,从而更新Fiber节点的状态。
3.生成副作用链表:在这个阶段,React会生成一个副作用链表,用于记录所有需要在commit阶段执行的副作用操作,例如DOM更新、事件处理等。
Commit阶段
Commit阶段是React的第二个阶段,其主要任务是将更新内容应用到DOM树中,并执行所有副作用操作。在这个阶段,React会执行以下操作:
1.将更新内容应用到DOM树中:在这个阶段,React会将Fiber树中所有需要更新的节点的变更应用到DOM树中,从而更新界面。
2.执行副作用操作:在这个阶段,React会执行之前生成的副作用链表中的所有副作用操作,例如事件处理、DOM更新等。
3.生命周期钩子函数调用:在这个阶段,React会根据之前生成的副作用链表中的操作顺序,依次调用组件的生命周期钩子函数,例如componentDidMount等。
总之,Render阶段是用于生成Fiber树并计算组件状态的阶段,而Commit阶段是用于将更新内容应用到DOM树中,执行副作用操作和生命周期钩子函数调用的阶段。两个阶段的任务是不同的,但是它们之间是相互依赖和影响的。
react调和过程为什么是用的双缓冲树结构
React调和过程中采用了双缓冲树结构,主要是为了避免频繁的DOM操作和提高页面渲染的性能。
双缓冲树结构是指React使用两个虚拟DOM树,一个用于当前页面的展示,另一个用于计算需要进行更新的部分。React将计算好的更新部分与当前页面的展示进行比较,只对有变化的部分进行更新,从而减少DOM操作的次数,提高了页面的渲染性能。
在React的调和过程中,首先会生成新的虚拟DOM树,然后通过对比新旧虚拟DOM树的差异,计算需要更新的部分。计算出的更新部分会被放入一个队列中,然后通过调度机制执行更新操作,具体的执行过程是在渲染阶段和提交阶段进行的。
在渲染阶段,React会遍历更新队列,根据更新类型和组件优先级进行任务调度和分片处理,执行相应的计算和副作用操作,同时会生成新的虚拟DOM树,并将其放入缓冲区中。
在提交阶段,React会将缓冲区中的虚拟DOM树与当前页面展示的虚拟DOM树进行比较,找到差异部分并执行更新操作,从而实现页面的渲染。
双缓冲数结构的优点是可以避免频繁的DOM操作,同时通过调度机制和任务分片的方式,可以使更新操作更加高效,提高了页面渲染的性能。