认识react16的fiber架构

认识react16的fiber架构

前言

React的Virtual DOM(VDOM),其核心的协调算法,即reconciliation,通过对比前后的Virtual DOM得出最小更新部分,再去渲染真实DOM,减少了频繁操作DOM的成本,使其深受大家关注。但随着前端工程化的发展,在大型的项目上reconciliation越来越不得满足,因此,React团队对reconciliation做出了优化,即Fiber架构。

React 渲染页面分为两个阶段:

  • 调度阶段(reconciliation):在这个阶段 React 会更新数据生成新的 Virtual DOM,然后通过 Diff 算法,快速找出需要更新的元素,放到更新队列中去,得到新的更新队列。
  • 渲染阶段(commit):这个阶段 React 会遍历更新队列,将其所有的变更一次性更新到 DOM 上。

react16之前

reconciler(被称为 stack reconciler ),以tree为单位,调度阶段(reconciliation)和渲染阶段(commit)按顺序执行,相当于没分阶段,形成同步渲染,采用自顶向下递归,从根组件或 setState() 后的组件开始,更新整个子树。如果组件层级深,组件树很大,就会一直占用浏览器主线程,导致布局、动画以及交互事件无法响应。

假如我们更新一个 state,有 1000 个组件需要更新,每个组件更新需要 1ms,那么我们就会有将近 1s 的时间,主线程被 React 占着用来调度,这段时间内用户的操作不会得到任何的反馈,只有当 React 中需要同步更新的任务完成后,主线程才被释放。对于这 1s 内 React 的调度,我们是无能为力的。

整个调度过程就如下图所示,组件树一旦过大,就会出现浏览器失去响应的情况,用户体验非常差。
fiber0

react16之后

reconciler(被称为 fiber reconciler )为了解决主线程阻塞问题,使用了Fiber架构,以fiber(fiber tree)为单位,Fiber可以在调度阶段(reconciliation)对fiber tree做调度处理,行成异步渲染,但渲染阶段(commit)不能调度不能暂停。
Fiber
Fiber的出现使大量的同步计算可以被拆解、异步化,使浏览器主线程得以调控。从而使我们得到了以下权限:

  • 暂停运行任务。
  • 恢复并继续执行任务。
  • 给不同的任务分配不同的优先级。
    把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

Fiber 把更新过程碎片化,即把state更新任务拆分成多个时间小片,形成一个 Fiber 任务队列,执行过程如下面的图所示。
每执行完一段更新过程,就把控制权交还给 React 负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有优先级更高的任务,那就去做优先级高的任务。
fiber1

调度阶段(reconciliation):Fiber调度
Fiber 在调度的时候会执行如下流程:

  1. 将一个state更新任务拆分成多个时间小片,形成一个 Fiber 任务队列.
  2. 在任务队列中选出优先级高的 Fiber 执行,如果执行时间超过了deathLine,则设置为pending状态挂起状态(即执行一段时间,会跳出找Fiber任务队列中更高级的任务,如果有就放弃当前任务,即使当前任务执行了一半,可能已经经历了一些生命周期,都会被打断从来)。
    此过程,React 在 workinProgress Tree (并不是真实的virtualDomTree)上复用 current 上的 Fiber 数据结构来异步地(通过requestIdleCallback)来构建新的 tree,标记处需要更新的节点,放入队列中。
  3. 一个 Fiber 执行结束或挂起,会调用基于requestIdleCallback/requestAnimationFrame实现的调度器,返回一个新的 Fiber 任务队列继续进行上述过程
    fiber2

requestIdleCallback 会让一个低优先级的任务在空闲期被调用
requestAnimationFrame 会让一个高优先级的任务在下一个栈被调用,从而保证了主线程按照优先级执行 fiber 单元
不同类型的任务会被分配不同的优先级,以下是关于优先级的定义:

module.exports = {  
  // heigh level
  NoWork: 0, // No work is pending.
  SynchronousPriority: 1, // For controlled text inputs. 
  TaskPriority: 2, // Completes at the end of the current tick.
  AnimationPriority: 3, // Needs to complete before the next frame.
  
  // low level
  HighPriority: 4, // Interaction that needs to complete pretty soon to feel responsive.
  LowPriority: 5, // Data fetching, or result from updating stores.
  OffscreenPriority: 6, // Won't be visible but do the work in case it becomes visible.
};

由此我们可以看出Fiber任务的优先级顺序为:
文本框输入 > 本次调度结束需完成的任务 > 动画过渡 > 交互反馈 > 数据更新 > 不会显示但以防将来会显示的任务

渲染阶段(commit):
进入render函数,构建真实的virtualDomTree,React将其所有的变更一次性更新到DOM上。

本文参考并转载于有赞云技术博客:浅谈 React 16 中的 Fiber 机制
https://developers.youzanyun.com/article/1557135472024?p=1&m=0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值