react源码学习

fiber架构的设计理念

1、fiber概述
在现有React中,更新过程是同步的,这可能会导致性能问题。

当React决定要加载或者更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者更新过程开始,那React就会一鼓作气运行到底,中途绝不停歇。在此过程中浏览器渲染引擎处于挂起的状态,无法进行任何渲染,浏览器无法执行任何其他的任务,调用栈如下图
react源码学习_第1张图片
破解javascript中同步操作时间过长的方法其实很简单——分片。

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

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

有了分片之后,更新过程的调用栈如下图所示,中间每一个波谷代表深入某个分片的执行过程,每个波峰就是一个分片执行结束交还控制权的时机。
react源码学习_第2张图片
维护每一个分片的数据结构,就是Fib

Fiber = {
  tag, // 标记不同的组件类型
  key, // ReactElement里面的key
  elementType, // ReactElement.type,也就是我们调用`createElement`的第一个参数
  type, // 一般是`function`或者`class`
  stateNode, // 在浏览器环境,就是DOM节点

  return, // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
  child, // 单链表树结构,指向自己的第一个子节点
  sibling, // 指向自己的兄弟结构,兄弟节点的return指向同一个父节点
  index,
  ref, // ref属性

  pendingProps, // 即将更新的props
  memoizedProps, // 更新props
  memoizedState, // 当前状态
  dependencies, // 一个列表,存放这个Fiber依赖的context

  flags, // Effect,用来记录当前fiber的tag,插入、删除、更新的状态
  subtreeFlags,
  deletions,
  updateQueue, // 该Fiber对应的组件产生的Update会存放在这个队列里面
  nextEffect, // 单链表用来快速查找下一下side effect
  firstEffect, // 自述中第一个side effect
  lastEffect, // 子树中最后一个side effect

  lanes, // 当前Fiber更新的优先级
  childLanes,
  // 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber
  // 我们称他为`current <==> workInProgress`
  // 在渲染完成之后他们会交换位置
  alternate,

  // 用来描述当前Fiber和他子树的`Bitfield`
  // 共存的模式表示这个子树是否默认是异步渲染的
  // Fiber被创建的时候他会继承父Fiber
  // 其他的标识也可以在创建的时候被设置
  // 但是在创建之后不应该再被修改,特别是他的子Fiber创建之前
  mode,
  // 其余为调试相关的,收集每个Fiber和子树渲染时间的
  //...
}

在react-hooks源码解析中我们主要涉及到memoizedState、updateQueue、flags字段。

setState具体实现

(1)首次渲染主要是初始化hook,将初始值存入hook内,将hook插入到fiber.memoizedState的末尾。

(2)setCount主要是将更新信息插入到hook.queue.penging的末尾。这里注意一下为什么没有直接更新hook.memoizedState呢?答案是react是批量更新的,需要将更新信息先存储下来,等到合适的时机统一计算更新。

(3)再次渲染主要是根据setCount存储的更新信息来计算最新的state。

为什么只能在函数最外层调用 Hook?为什么不要在循环、条件判断或者子函数中调用?

react 会生成一棵组件树(或Fiber 单链表)将hook插入到fiber.memoizedState的末尾。通过单链表的 next指针 按顺序串联所有的 hook。 所有memoizedState 数组是按 hook定义的顺序来放置数据的,如果 hook 顺序变化,memoizedState 并不会感知到。

你可能感兴趣的:(react.js,学习,javascript)