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

React 深入之 Fiber #82

Open
george-es opened this issue Jan 13, 2021 · 0 comments
Open

React 深入之 Fiber #82

george-es opened this issue Jan 13, 2021 · 0 comments
Labels
react unknow 未解决的问题

Comments

@george-es
Copy link
Owner

fiber 是什么?

fiber 是对核心算法的一次重新实现

为什么要有 fiber 呢?

同步更新的局限:fiber 还没出来之前,React 的更新过程是同步的,每次加载或更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新 DOM 树,这一系列操作,打比方,更新一个组件要 1 毫秒,200 个组件就要 200 毫秒,在 200 毫秒内,任何操作都会中断,从而导致卡顿现象,而在 fiber 中,则通过 "分片" 这一手段解决的。

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

React Fiber把更新过程碎片化,每执行完一段更新过程,就把控制权交还给React负责任务协调的模块,看看有没有其他紧急任务要做,如果没有就继续去更新,如果有紧急任务,那就去做紧急任务。

维护每一个分片的数据结构,就是Fiber。

写代码时对 fiber 的思考

我们知道 Fiber 影响着任务的调度机制,在 React Fiber 中,一次更新过程会分成多个分片完成,所以完全有可能一个更新任务还没有完成,就被另一个更高的优先级更新过程打断了,这时候,优先级高的更新任务会优先处理完,而低优先级的更新任务所做的工作则会完全作废,然后等待机会重头再来。注意,是完全作废,重头再来,而不是中断地方再来

因此一个更新过程被打断了,所以 Fiber 的更新过程分为两个阶段(Phase):第一阶段 Reconciliation Phase 和第二阶段 Commit Phase。

在第一阶段 Reconciliation Phase,React Fiber 会找出需要更新哪些 DOM,这个阶段是可以被打断的;但是到了第二阶段 Commit Phase,那就一鼓作气把 DOM 更新完,绝不会被打断。

每个阶段做了什么事,有兴趣的同学可以深入了解,我们只需知道,现在的 React 更新过程是会被打断的,高优先级会打断低优先级任务,和我们相关的也就是生命周期函数了

以 render 函数为界,第一阶段可能会调用下面这些生命周期函数

  • componentWillMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate

而第二阶段则会在第二阶段调用

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

因为第一阶段的过程会被打断而且”重头再来“,就会造成意想不到的情况

比如说一个低优先级的任务 A 正在进行,已经调用了某个组件的 componentWillUpdate 函数,接下来发现自己的时间分片已经用完了,于是 Fiber 会看看有没有优先级更高的任务,此时有个任务 B 需要紧急执行,Fiber 就去执行任务 B 了,虽然 A 执行到了一半,没办法,只能放弃,等 B 任务执行完毕后,再重新执行 A 任务,也就是说 componentWillUpdate 函数会再调用一次。因此在 Fiber 中,第一阶段中的生命周期函数在一次加载和更新过程中可能会被多次调用,这就很好解释,为什么异步请求要放在 componentDidMount 中,而不是放在 componentWillMount 中了

上面我们大概了解了 Fiber 带来的好处以及在写代码过程中需要的思考,下面我们来深度了解下 Fiber


深度解剖 Fiber

目标

Fiber 的核心目标是扩大其适用性,包括动画,布局和手势,主要分为 5 个具体目标

  • 把可中断的工作拆成小任务
  • 对正在做的工作调整优先次序,重做,复用上次(做了一半的)成果
  • 在父子任务之间从容切换,以支持React执行过程中的布局刷新
  • 支持 render 返回多个元素
  • 更好地支持 error boundary

所以 Fiber 的初衷就是不希望JS不受控制地长时间执行(想要手动调度),JS长时间执行会影响交互响应、动画,因为 因为JavaScript在浏览器的主线程上运行,恰好与样式计算、布局以及许多情况下的绘制一起运行。如果JavaScript运行时间过长,就会阻塞这些其他工作,可能导致掉帧

特性

Fiber 的关键特性如下

  • 增量渲染(把渲染任务拆分成块,匀到多帧)
  • 更新时能够暂停,终止,复用渲染任务
  • 给不同类型的更新赋予优先级
  • 并发方面新的基础能力

增量渲染用来解决掉帧的问题,渲染任务拆分之后,每次只做一小段,做完一段就把时间控制权交还给主线程,而不像之前长时间占用,这种策略叫做cooperative scheduling(合作式调度)。

@george-es george-es added react unknow 未解决的问题 labels Jan 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
react unknow 未解决的问题
Projects
None yet
Development

No branches or pull requests

1 participant