Fiber的理解

Fiber的理解

代数效应

React 团队核心成员 – React hooks 的发明者 Sebastian Markbage 曾说:在 react 中做的就是践行代数效应

代数效应:是函数式编程中的概念,用于将副作用从函数调用中分离,使函数的关注点保持纯粹


React 如何应用代数效应: 代数效应和 react 中的联系就是 hooks

举个🌰:使用 useState 返回了一个 num 和 updatenum 的方法,num的值会显示在 button 中,点击btn后num值会加1,我们只需要考虑num如何展示以及更新逻辑是怎么样的,至于num是如何保存在函数式组件的这些完全交给 react去处理,实现了将副作用从函数调用中分离。


fiber 架构与代数效应的关系

fiber架构就是利用了代数效应中 异步可中断更新的原理(async 的执行原理就是类似于 异步可中断更新机制,但是有一定区别)


fiber 架构

在这里插入图片描述

fiber 翻译过来是纤程,与进程,线程,协程同为操作系统程序的执行过程,可以将纤程理解为协程的一种实现,(协程在js中有一个应用,就是 generator 的实现)


为什么不选择协程实现异步可中断

那为什么不使用 协程来实现异步可中断的更新,而要自己实现一套纤程呢?

16年在 github 上有一篇 fiber 的 issue 文章中找到了答案:
在这里插入图片描述

  1. generator 也和 async await 一样,也是有传染性的,当某个函数变成 generator 后,调用链的其他函数也会收到影响
  2. 第二个,也是最重要的原因,设计 fiber 架构的初衷是为了达到两个目的
    1. 更新可以被中断,也可以继续
    2. 更新可以拥有不同的优先级,高优先级的可以打断低优先级的更新

使用 generator 可以达到 2.1 的目的,但是不能达到2.2的目的


fiber 的含义

作为架构来说

react 15 的协调器(reconciler)采用递归的方式执行,数据保存在递归的调用栈中,所以其实也被称为 stack reconciler。
react 16 的调节器是基于 fiber 节点实现的,所以被称为 fiber reconciler。


作为静态的数据结构来说

每个 fiber 节点对应一个组件,保存了该组件的类型和对应的dom节点信息,这时的fiber节点也就是我们所说的虚拟 dom,

举个例子:比如说有个 app组件,当我们首次调用 reactdom.render 时,会创建整个应用的根结点FiberRootNode ,由于我们可以多次调用 render 方法,将不同的应用挂载到不同的 dom 节点下,所以每个应用都有自己的 RootFiber 节点,在一个页面中有多个 rootfiber 节点,但是只能有一个FiberRootNode 来管理这些 RootFiber

在这里插入图片描述

可能会问,为啥子节点是child,父节点确是用 return 来连接呢?

因为 react15 中的 stack reconciler 采用递归的方式工作,当从根结点开始执行递归操作时,首先会从根结点一直递归到子节点,再从子节点一路向上回到根结点,所以函数在处理完了了子节点之后,会返回他的父节点;在 fiber reconciler 中,采用遍历的欣赏,实现可中断的递归,所以也复用了这种思想,所以就用return 代表了父节点。

在这里插入图片描述

如果只是作为静态的数据结构,fiber 和 jsx 没有什么区别


作为动态的工作单元

fiber 节点保存了组件需要更新的状态以及需要执行的副作用,依次是作为静态数据结构,作为架构来说(return,child,sibling 指针会将fiber节点连接成一个树),作为动态的工作单元(其中带有 effect 的是代表副作用相关的,对于 host component ,副作用有增删改查,对于 function component,副作用代表的是 useEffect 和 uselayoutEffect 这两个hook,和 lane 相关的属性和 优先级调度有关,最后一个 alternate 属性关系到了 fiber 架构的工作方式

在这里插入图片描述


fiber 的工作机制:双缓存

fiber 架构使用一种叫双缓存的工作机制


双缓存:
首先了解动画的原理:动画由多张连续的图片组成,每一张图称为动画的一帧,当我们播放动画时,以一定的速度连续展示每一帧的图片,在动画的展示区域,在渲染新的一帧时会将前一帧的图片清除,如果从清除前一帧图片到展示下一帧的图片消耗的时间过长,就会出现人眼能感知的白屏闪烁,为解决这个问题,出现了 双缓存。

在内存中绘制当前帧的图片,绘制完成后,直接用当前帧替换上一帧的图片,由于省出来两帧替换帧所消耗的时间,不会出现白屏或者画面闪烁的情况,这种在内存中构建并直接替换的技术就叫双缓存


双缓存工作原理
  1. 当首次调用 ReactDOM.render 时,会创建整个应用的根结点 FiberRootNode;每次调用 ReactDOM.render,都会创建当前应用的根结点 RoottFiber,通过 current 指针连接,由于在首屏渲染之前,页面是空白的,所以 RootFiber 没有子节点

  1. 无论是首屏渲染还是更新,都会从根节点开始创建一个 fiber 树,首先创建 fiber树的根节点 RootFiber,这两棵fiber树中都存在 fiber节点,会用 alternate 指针连接,方便两棵fiber树之间共用一些属性,接下来采用深度优先遍历,模拟递归的方式创建整棵 fiber 树。现在拥有两棵fiber树,左侧代表页面内容的fiber树 current Fiber 树,右侧由于触发了更新,在内存中构建的 fiber树称为 workInProgress Fiber 树

在这里插入图片描述

  1. 当 workInProgress fiber 树完成了渲染,此时 FiberRootNode 的 current 指针就指向了workInProgress fiber 树的根节点,于是 workInProgress fiber 树 就变成了 current fiber 树

每次触发更新,都会重新创建一个 workInProgress fiber 树,将 current fiber 树 的节点称为 current 节点,此时 current RootFiber 的 alternate 指针已经指向了一个 RootFiber,所以在创建新的 workInProgress fiber 树时,会基于这个 RootFiber 创建。

这种将 current fiber 与本次更新返回的 JSX 结构进行对比生成 workInProgress fiber 树的过程就是 diff 算法,所以首屏渲染与更新的区别就是在创建 fiber 树的过程中 是否有 diff 算法


  1. 当 workInProgress fiber 树最终完成了渲染,current 指针指向了 workInProgress 的根节点,至此,当前的 workInProgress fiber 树 变为了 current fiber 树

总结

在这里插入图片描述


参考文献:
https://github.com/acdlite/react-fiber-architecture
https://www.bilibili.com/video/BV1vP4y1w7TN
https://ke.segmentfault.com/course/1650000023864436/section/1500000023865956

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值