Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reacte 的 Fiber 概念 #13

Open
oliver1204 opened this issue Feb 14, 2019 · 0 comments
Open

reacte 的 Fiber 概念 #13

oliver1204 opened this issue Feb 14, 2019 · 0 comments

Comments

@oliver1204
Copy link
Owner

React目前面临的挑战

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

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

现有React一个非常大的问题是调度阶段是不可控的,什么意思?

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

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

Fiber解决方案

Fiber 的中文解释是纤程,是线程的颗粒化的一个概念。也就是说一个线程可以包含多个 Fiber。

Fiber 的出现使大量的同步计算可以被拆解、异步化,使浏览器主线程得以调控。从而使我们得到了以下权限:

  • 暂停运行任务。
  • 恢复并继续执行任务。
  • 给不同的任务分配不同的优先级。

把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

Fiber的实现原理

React Fiber 的做法是不使用 Javascript 的栈,而是将需要执行的操作放在自己实现的栈对象上。这样就能在内存中保留栈帧,以便更加灵活的控制调度过程,例如我们可以手动操纵栈帧的调用。这对我们完成调度来说是至关重要。

大致上 Fiber 在调度的时候会执行如下流程:

  1. 一个state更新需要执行的同步任务拆分成一个Fiber任务队列
  2. 在任务队列中选出优先级高的Fiber执行,如果执行时间超过了deathLine,则设置为pending状态挂起状态
  3. 一个Fiber执行结束或挂起,会调用基于requestIdleCallback/requestAnimationFrame实现的调度器,返回一个新的Fiber任务队列继续进行上述过程

requestIdleCallback会让一个低优先级的任务在空闲期被调用,而requestAnimationFrame会让一个高优先级的任务在下一个栈帧被调用,从而保证了主线程按照优先级执行Fiber单元。

不同类型的任务会被分配不同的优先级,以下是关于优先级的定义:

module.exports = {  
  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.
  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任务的优先级顺序为:

文本框输入 > 本次调度结束需完成的任务 > 动画过渡 > 交互反馈 > 数据更新 > 不会显示但以防将来会显示的任务

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant