六个问题让你更懂 React Fiber(下)

简介: 接上文。

Fiber 结构长什么样?


基于时间分片的增量更新需要更多的上下文信息,之前的vDOM tree显然难以满足,所以扩展出了fiber tree(即Fiber上下文的vDOM tree),更新过程就是根据输入数据以及现有的fiber tree构造出新的fiber tree(workInProgress tree)。


FiberNode 上的属性有很多,根据笔者的理解,以下这么几个属性是值得关注的:return、child、sibling(主要负责fiber链表的链接);stateNode;effectTag;expirationTime;alternate;nextEffect。各属性介绍参看下面的class FiberNode


class FiberNode {
  constructor(tag, pendingProps, key, mode) {
    // 实例属性
    this.tag = tag; // 标记不同组件类型,如函数组件、类组件、文本、原生组件...
    this.key = key; // react 元素上的 key 就是 jsx 上写的那个 key ,也就是最终 ReactElement 上的
    this.elementType = null; // createElement的第一个参数,ReactElement 上的 type
    this.type = null; // 表示fiber的真实类型 ,elementType 基本一样,在使用了懒加载之类的功能时可能会不一样
    this.stateNode = null; // 实例对象,比如 class 组件 new 完后就挂载在这个属性上面,如果是RootFiber,那么它上面挂的是 FiberRoot,如果是原生节点就是 dom 对象
    // fiber
    this.return = null; // 父节点,指向上一个 fiber
    this.child = null; // 子节点,指向自身下面的第一个 fiber
    this.sibling = null; // 兄弟组件, 指向一个兄弟节点
    this.index = 0; //  一般如果没有兄弟节点的话是0 当某个父节点下的子节点是数组类型的时候会给每个子节点一个 index,index 和 key 要一起做 diff
    this.ref = null; // reactElement 上的 ref 属性
    this.pendingProps = pendingProps; // 新的 props
    this.memoizedProps = null; // 旧的 props
    this.updateQueue = null; // fiber 上的更新队列执行一次 setState 就会往这个属性上挂一个新的更新, 每条更新最终会形成一个链表结构,最后做批量更新
    this.memoizedState = null; // 对应  memoizedProps,上次渲染的 state,相当于当前的 state,理解成 prev 和 next 的关系
    this.mode = mode; // 表示当前组件下的子组件的渲染方式
    // effects
    this.effectTag = NoEffect; // 表示当前 fiber 要进行何种更新(更新、删除等)
    this.nextEffect = null; // 指向下个需要更新的fiber
    this.firstEffect = null; // 指向所有子节点里,需要更新的 fiber 里的第一个
    this.lastEffect = null; // 指向所有子节点中需要更新的 fiber 的最后一个
    this.expirationTime = NoWork; // 过期时间,代表任务在未来的哪个时间点应该被完成
    this.childExpirationTime = NoWork; // child 过期时间
    this.alternate = null; // current 树和 workInprogress 树之间的相互引用
  }
}


1d54d3201c56c2db2be41c843d6281d3.png


function performUnitWork(currentFiber){
    //beginWork(currentFiber) //找到儿子,并通过链表的方式挂到currentFiber上,每一偶儿子就找后面那个兄弟
  //有儿子就返回儿子
  if(currentFiber.child){
    return currentFiber.child;
  } 
  //如果没有儿子,则找弟弟
  while(currentFiber){//一直往上找
    //completeUnitWork(currentFiber);//将自己的副作用挂到父节点去
    if(currentFiber.sibling){
      return currentFiber.sibling
    }
    currentFiber = currentFiber.return;
  }
}


Concurrent Mode (并发模式)


Concurrent Mode 指的就是 React 利用上面 Fiber 带来的新特性的开启的新模式 (mode)。react17开始支持concurrent mode,这种模式的根本目的是为了让应用保持cpu和io的快速响应,它是一组新功能,包括Fiber、Scheduler、Lane,可以根据用户硬件性能和网络状况调整应用的响应速度,核心就是为了实现异步可中断的更新。concurrent mode也是未来react主要迭代的方向。


目前 React 实验版本允许用户选择三种 mode:


  1. Legacy Mode: 就相当于目前稳定版的模式


  1. Blocking Mode: 应该是以后会代替 Legacy Mode 而长期存在的模式


  1. Concurrent Mode: 以后会变成 default 的模式


Concurrent Mode 其实开启了一堆新特性,其中有两个最重要的特性可以用来解决我们开头提到的两个问题:


  1. Suspense[14]:Suspense 是 React 提供的一种异步处理的机制, 它不是一个具体的数据请求库。它是React 提供的原生的组件异步调用原语。


  1. useTrasition[15]:让页面实现 Pending -> Skeleton -> Complete 的更新路径, 用户在切换页面时可以停留在当前页面,让页面保持响应。相比展示一个无用的空白页面或者加载状态,这种用户体验更加友好。


其中 Suspense 可以用来解决请求阻塞的问题,UI 卡顿的问题其实开启 concurrent mode 就已经解决的,但如何利用 concurrent mode 来实现更友好的交互还是需要对代码做一番改动的。


未来可期


Concurrent Mode只是并发,既然任务可拆分(只要最终得到完整effect list就行),那就允许并行执行,(多个Fiber reconciler + 多个worker),首屏也更容易分块加载/渲染(vDOM森林。


并行渲染的话,据说Firefox测试结果显示,130ms的页面,只需要30ms就能搞定,所以在这方面是值得期待的,而React已经做好准备了,这也就是在React Fiber上下文经常听到的待unlock的更多特性之一。


isInputPending —— Fiber架构思想对前端生态的影响


Facebook 在 Chromium 中提出并实现了 isInputPending() API,它可以提高网页的响应能力,但是不会对性能造成太大影响。Facebook 提出的 isInputPending API 是第一个将中断的概念用于浏览器用户交互的的功能,并且允许 JavaScript 能够检查事件队列而不会将控制权交于浏览器。


目前 isInputPending API 仅在 Chromium 的 87 版本开始提供,其他浏览器并未实现。


e9bc38ec0964273695aeddf18f2df7f7.png


Svelte 对固有模式的冲击


当下前端领域,三大框架React、Vue、Angular版本逐渐稳定,如果说前端行业会出现哪些框架有可能会挑战React或者Vue呢?很多人认为Svelte 应该是其中的选项之一。


Svelte叫法是[Svelte], 本意是苗条纤瘦的,是一个新兴热门的前端框架。在开发者满意度、兴趣度、市场占有率上均名列前茅,同时,它有更小的打包体积,更少的开发代码书写,在性能测评中,与React、Vue相比,也不遑多让。


Svelte 的核心思想在于『通过静态编译减少框架运行时的代码量』。


Svelte 优势有哪些


  • No Runtime —— 无运行时代码


  • Less-Code —— 写更少的代码


  • Hight-Performance —— 高性能


Svelte 劣势


  • 社区


  • 社区


  • 社区


原理概览


Svelte 在编译时,就已经分析好了数据 和 DOM 节点之间的对应关系,在数据发生变化时,可以非常高效的来更新DOM节点。


  • Rich Harris 在进行Svelte的设计的时候没有采用 Virtual DOM,主要是因为他觉得Virtual DOM Diff 的过程是非常低效的。具体可参考Virtual Dom 真的高效吗[21]一文;Svelte 采用了Templates语法,在编译的过程中就进行优化操作;


  • Svelte 记录脏数据的方式:位掩码(bitMask);


  • 数据和DOM节点之间的对应关系:React 和 Vue 是通过 Virtual Dom 进行 diff 来算出来更新哪些 DOM 节点效率最高。Svelte 是在编译时候,就记录了数据 和 DOM 节点之间的对应关系,并且保存在 p 函数中。


e727859dc422c2cf156c33f5fca358e7.png


写在最后


我是零一,如果我的文章对你有帮助,请点个 👍🏻 支持我一下

相关文章
|
8月前
|
前端开发
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍2
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍2
37 0
|
4月前
|
移动开发 前端开发 JavaScript
react fiber架构【详细讲解,看这一篇就够了】
react fiber架构【详细讲解,看这一篇就够了】
170 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第五十七天-react源码-Fiber数据结构介绍2
前端学习笔记202307学习笔记第五十七天-react源码-Fiber数据结构介绍2
37 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第五十七天-react源码-Fiber数据结构介绍1
前端学习笔记202307学习笔记第五十七天-react源码-Fiber数据结构介绍1
45 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍
52 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第六十天-react源码-子级节点Fiber对象的构建流程
前端学习笔记202307学习笔记第六十天-react源码-子级节点Fiber对象的构建流程
47 0
前端学习笔记202307学习笔记第六十天-react源码-子级节点Fiber对象的构建流程
|
8月前
|
前端开发
前端学习笔记202307学习笔记第六十天-react源码-构建多个子集fiber的情况
前端学习笔记202307学习笔记第六十天-react源码-构建多个子集fiber的情况
33 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第六十天-react源码-构建单个子集fiber的情况2
前端学习笔记202307学习笔记第六十天-react源码-构建单个子集fiber的情况2
30 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第六十天-react源码-构建单个子集fiber的情况1
前端学习笔记202307学习笔记第六十天-react源码-构建单个子集fiber的情况1
40 0
|
8月前
|
前端开发
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍2
前端学习笔记202307学习笔记第五十九天-react源码-Fiber数据结构介绍2
34 0