带你完全理解react fiber架构

先上一张整体架构图

简化了不少流程,这里只取主要流程 node

主流程解说

  1. 从render函数起步,render函数第一个参数将接受一个vdom-tree。
  2. 经过scheduleRoot开始调度,shceduleRoot会使用到workInProgressRoot,nextUnitOfWork,currentRoot以及workInProgressRoot.alternate这几个关键元素
  3. 咱们会经过requestIdleCallBack去执行wookloop(react中本身实现了该函数的polyfill,这里不会讲述)
  4. 经过! deadline.timeRemaining() < 1 && nextUnitOfWork,判断时间片是否还有剩余而且nextUnitOfWork任务还有剩余去循环执行performUnitOfWork(nextUnitOfWork),该函数的做用是生成fiber-tree以及收集更新时的依赖。
  5. 以上调度过程就是能够被打断的,当没有nextUnitOfWork时,将调用commitRoot更新页面

wookloop的流程详解

基于我发的总体架构图react

  1. workLoop函数会首先判断是否存在任务,而且该时间片是否使用完(在此咱们能够先不考虑时间片使用完成的状况),当任务存在,会调用performUnitOfWork,该函数会当即调用beginWork对当前fiberNode即nextUnitOfWork的子节点进行调和,生成新的fiber-tree。(这里只是部分fiber-tree造成)
  2. 当该节点调和完成,react会将currentFiber指向他的child,并将该节点return出去赋值给nextUnitOfWork再次调用wookLoop直到child为空。
  3. 此时从该节点开始收集依赖,(注意fiber-tree并无彻底造成),调用completeUnitOfWork(currentFiber)开始收集依赖,当该fiber-node依赖收集完成,react将该节点移向他的sibling节点,并将该节点赋值给nextUnitOfWork,再次调用performUnitOfWork,此时会生成该节点的fiber-tree,而且因为sibling节点没有child,将再次调用completeUnitOfWork收集该节点依赖。
  4. 在第3步中,若是sibling节点没有,react将会移动当前节点到到其父节点,再次经过completeUnitOfWork收集父节点依赖。
  5. 重复3,4过程直到当前节点为空,此时fiber-tree造成完成,依赖收集完成。
  6. 记住一点以上过程是经过requestIdleCallBack执行的,那么以上过程即可以被打断。

如何调和?

先上图片 缓存

流程解说

  1. 首先根据是否存在oldFiber来判断是不是第一次渲染,若是是接下来的判断都属于新增节点,若是不是那么会更具新老节点的diff比对造成新的fiber-tree,
  2. 比对时咱们会顺序遍历新老节点,(源码中会根据key造成map数据结构来比对节点)这里的比对方式和官网给出的说法是一致的,这里主要说的使一些性能上的优化,当react判断是第一次更新(不是第一次渲染),他会复用oldFiber,若是是第二次或者更屡次更新,react会复用用缓存在alternate节点上的老节点,从而生成新的fiber-tree
  3. 调和的目的就是造成新的fiber-tree

收集依赖?

再来看一张图片 数据结构

  1. 更具以上分析当开始调用completeUnitOfWork收集依赖时,该节点是最后一个child元素,从该元素开始,收集该元素的effect及其child的effect(最后一个元素无child)(整张图就是这个意思)
  2. 按照自己--->兄弟节点---->父节点的顺序向上遍历,直到rootFiber节点全部依赖收集完毕。(根据整个架构图推出)

提交fiberRoot

上图: 架构

  1. 当收集完依赖,咱们开始执行commitRoot,首先咱们删除须要删除的节点,接着会从fistEffect开始遍历更新页面dom节点
  2. 调用commitWork(currentFiber)更新此fiber的dom节点,首先咱们会寻找到该fiber节点的第一个父容器dom节点,在更具该节点effectTag来更新、删除或者除添加节点。
  3. 将effect指向下一个重读2过程,直到全部effect遍历完成。
相关文章
相关标签/搜索