学习串联渲染链路你能学到什么?
- 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 个兄弟节点。