带你完全理解react fiber架构
先上一张整体架构图
简化了不少流程,这里只取主要流程 node
主流程解说
- 从render函数起步,render函数第一个参数将接受一个vdom-tree。
- 经过scheduleRoot开始调度,shceduleRoot会使用到workInProgressRoot,nextUnitOfWork,currentRoot以及workInProgressRoot.alternate这几个关键元素
- 咱们会经过requestIdleCallBack去执行wookloop(react中本身实现了该函数的polyfill,这里不会讲述)
- 经过! deadline.timeRemaining() < 1 && nextUnitOfWork,判断时间片是否还有剩余而且nextUnitOfWork任务还有剩余去循环执行performUnitOfWork(nextUnitOfWork),该函数的做用是生成fiber-tree以及收集更新时的依赖。
- 以上调度过程就是能够被打断的,当没有nextUnitOfWork时,将调用commitRoot更新页面
wookloop的流程详解
基于我发的总体架构图react
- workLoop函数会首先判断是否存在任务,而且该时间片是否使用完(在此咱们能够先不考虑时间片使用完成的状况),当任务存在,会调用performUnitOfWork,该函数会当即调用beginWork对当前fiberNode即nextUnitOfWork的子节点进行调和,生成新的fiber-tree。(这里只是部分fiber-tree造成)
- 当该节点调和完成,react会将currentFiber指向他的child,并将该节点return出去赋值给nextUnitOfWork再次调用wookLoop直到child为空。
- 此时从该节点开始收集依赖,(注意fiber-tree并无彻底造成),调用completeUnitOfWork(currentFiber)开始收集依赖,当该fiber-node依赖收集完成,react将该节点移向他的sibling节点,并将该节点赋值给nextUnitOfWork,再次调用performUnitOfWork,此时会生成该节点的fiber-tree,而且因为sibling节点没有child,将再次调用completeUnitOfWork收集该节点依赖。
- 在第3步中,若是sibling节点没有,react将会移动当前节点到到其父节点,再次经过completeUnitOfWork收集父节点依赖。
- 重复3,4过程直到当前节点为空,此时fiber-tree造成完成,依赖收集完成。
- 记住一点以上过程是经过requestIdleCallBack执行的,那么以上过程即可以被打断。
如何调和?
先上图片 缓存
流程解说
- 首先根据是否存在oldFiber来判断是不是第一次渲染,若是是接下来的判断都属于新增节点,若是不是那么会更具新老节点的diff比对造成新的fiber-tree,
- 比对时咱们会顺序遍历新老节点,(源码中会根据key造成map数据结构来比对节点)这里的比对方式和官网给出的说法是一致的,这里主要说的使一些性能上的优化,当react判断是第一次更新(不是第一次渲染),他会复用oldFiber,若是是第二次或者更屡次更新,react会复用用缓存在alternate节点上的老节点,从而生成新的fiber-tree
- 调和的目的就是造成新的fiber-tree
收集依赖?
再来看一张图片 数据结构
- 更具以上分析当开始调用completeUnitOfWork收集依赖时,该节点是最后一个child元素,从该元素开始,收集该元素的effect及其child的effect(最后一个元素无child)(整张图就是这个意思)
- 按照自己--->兄弟节点---->父节点的顺序向上遍历,直到rootFiber节点全部依赖收集完毕。(根据整个架构图推出)
提交fiberRoot
上图: 架构
- 当收集完依赖,咱们开始执行commitRoot,首先咱们删除须要删除的节点,接着会从fistEffect开始遍历更新页面dom节点
- 调用commitWork(currentFiber)更新此fiber的dom节点,首先咱们会寻找到该fiber节点的第一个父容器dom节点,在更具该节点effectTag来更新、删除或者除添加节点。
- 将effect指向下一个重读2过程,直到全部effect遍历完成。
欢迎关注本站公众号,获取更多信息