学习串联渲染链路你能学到什么?
- React 16 在所有状况下都是异步渲染的吗?
- Fiber 架构中的“可中断”“可复原”到底是如何实现的?
- Fiber 树和传统虚构 DOM 树有何不同?
- 优先级调度又是如何实现的?
ReactDOM.render 调用栈
ReactDOM.render 调用栈大抵能够拆分成如下三个阶段:
- 初始化阶段
- render阶段
- commit阶段
初始化阶段
实现Fiber树中根本实体的创立,哪什么是Fiber,它是干啥的,根本实体又是什么?
Fiber是什么?
Fiber是对React外围算法的重构。
Fiber的作用?
- 把可中断的工作拆分小工作
- 对正在操作的工作调整优先秩序、重做、复用
- 在父子工作之间切换,以反对React执行过程中的布局刷新
- 反对render返回多个元素
根本实体是什么?
技根底实体想要理解他,来看一段源码
function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) { // container 对应的是咱们传入的实在 DOM 对象 var root = container._reactRootContainer; // 初始化 fiberRoot 对象 var fiberRoot; // DOM 对象自身不存在 _reactRootContainer 属性,因而 root 为空 if (!root) { // 若 root 为空,则初始化 _reactRootContainer,并将其值赋值给 root root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate); // legacyCreateRootFromDOMContainer 创立出的对象会有一个 _internalRoot 属性,将其赋值给 fiberRoot fiberRoot = root._internalRoot; // 这里解决的是 ReactDOM.render 入参中的回调函数,你理解即可 if (typeof callback === 'function') { var originalCallback = callback; callback = function () { var instance = getPublicRootInstance(fiberRoot); originalCallback.call(instance); }; } // Initial mount should not be batched. // 进入 unbatchedUpdates 办法 unbatchedUpdates(function () { updateContainer(children, fiberRoot, parentComponent, callback); }); } else { // else 逻辑解决的是非首次渲染的状况(即更新),其逻辑除了跳过了初始化工作,与楼上基本一致 fiberRoot = root._internalRoot; if (typeof callback === 'function') { var _originalCallback = callback; callback = function () { var instance = getPublicRootInstance(fiberRoot); _originalCallback.call(instance); }; } // Update updateContainer(children, fiberRoot, parentComponent, callback); } return getPublicRootInstance(fiberRoot);}
在这段源码中次要的操作就是赋值fiberRoot对象,这个对象是通过root._internalRoot赋值,实质上这个对象是一个FiberRootNode对象,其中蕴含一个current对象,这个对象是FiberNode实例。而 FiberNode,正是 Fiber 节点对应的对象类型。current 对象是一个 Fiber 节点,不仅如此,它还是以后 Fiber 树的头部节点。其中,fiberRoot 的关联对象是实在 DOM 的容器节点;而 rootFiber 则作为虚构 DOM 的根节点存在。这两个节点,将是后续整棵 Fiber 树构建的终点。
整个初始化的工作过程都是在为后续的 render 阶段做筹备。当初,咱们的 Fiber Tree 还处在只有根节点的起始状态。接下来,咱们就要进入到最最要害的 render 阶段里去,一起去看看这棵树是怎么一点点开枝散叶的吧!
render阶段
scheduleUpdateOnFiber 办法的作用是调度更新,在由 ReactDOM.render 发动的首屏渲染这个场景下,它触发的就是 performSyncWorkOnRoot。performSyncWorkOnRoot 开启的正是咱们反复强调的 render 阶段;finishSyncRoot标记着render办法的完结。在这个过程中,交叉了大量了beginWork、completeWork调用(这两个办法串联起来就是一个模仿递归的过程)。这个两个办法就是render的工作内容。
在React15中和谐是一个递归的过程。在Fiber架构下,尽管不依赖递归,然而ReactDOM.render模式下,他整体是一个同步过程,是一个优先深度遍历。在这个过程中beginWork是负责创立Fiber节点,completeWork负责将Fiber节点映射为实在DOM。
接下来来看看这个过程有那些比拟重要的调用
performSyncWorkOnRoot:开始render阶段
renderRootSync:筹备工作
prepareFreshStack:重置一个新的堆栈环境
这里比拟重要的是调用了createWorkInProgress这个函数,咱们来看看这个函数干了什么
createWorkInProgress
workLoopSync:通过 while 循环反复判断 workInProgress 是否为空,并在不为空的状况下针对它执行 performUnitOfWork 函数。
performUnitOfWork:触发对beginWork的调用。performUnitOfWork,其次要工作是“通过调用 beginWork,来实现新 Fiber 节点的创立”;它还有一个主要工作,就是把新创建的这个 Fiber 节点的值更新到 workInProgress 变量里去。
beginWork:创立Fiber节点
beginWork 的外围逻辑是依据 fiber 节点(workInProgress)的 tag 属性的不同,调用不同的节点创立函数。在beginWork前面还有很多逻辑,感兴趣的同学能够深挖,借鉴网上的一张图如下:
Fiber 节点间是如何连贯
不同的 Fiber 节点之间,将通过 child、return、sibling 这 3 个属性建设关系,其中 child、return 记录的是父子节点关系,而 sibling 记录的则是兄弟节点关系。FiberNode 实例中,return 指向的是以后 Fiber 节点的父节点,而 sibling 指向的是以后节点的第 1 个兄弟节点。