学习串联渲染链路你能学到什么?


  • 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 个兄弟节点。

后续

下一章持续为大家来分享ReactDOM.render串联渲染链路
感激修言大神的《深入浅出搞定 React》