react源码解析6.legacy模式和concurrent模式

视频解说(高效学习):进入学习

往期文章:

1.开篇介绍和面试题

2.react的设计理念

3.react源码架构

4.源码目录构造和调试

5.jsx&外围api

6.legacy和concurrent模式入口函数

7.Fiber架构

8.render阶段

9.diff算法

10.commit阶段

11.生命周期

12.状态更新流程

13.hooks源码

14.手写hooks

15.scheduler&Lane

16.concurrent模式

17.context

18事件零碎

19.手写迷你版react

20.总结&第一章的面试题解答

react启动的模式

react有3种模式进入主体函数的入口,咱们能够从 react官网文档 应用 Concurrent 模式(实验性)中比照三种模式:

  • legacy 模式: ReactDOM.render(<App />, rootNode)。这是以后 React app 应用的形式。以后没有打算删除本模式,然而这个模式可能不反对这些新性能。
  • blocking 模式: ReactDOM.createBlockingRoot(rootNode).render(<App />)。目前正在试验中。作为迁徙到 concurrent 模式的第一个步骤。
  • concurrent 模式: ReactDOM.createRoot(rootNode).render(<App />)。目前在试验中,将来稳固之后,打算作为 React 的默认开发模式。这个模式开启了所有的新性能。

个性比照:

legacy 模式在合成事件中有主动批处理的性能,但仅限于一个浏览器工作。非 React 事件想应用这个性能必须应用 unstable_batchedUpdates。在 blocking 模式和 concurrent 模式下,所有的 setState 在默认状况下都是批处理的。会在开发中收回正告

不同模式在react运行时的含意

legacy模式是咱们罕用的,它构建dom的过程是同步的,所以在render的reconciler中,如果diff的过程特地耗时,那么导致的后果就是js始终阻塞高优先级的工作(例如用户的点击事件),体现为页面的卡顿,无奈响应。

concurrent Mode是react将来的模式,它用工夫片调度实现了异步可中断的工作,依据设施性能的不同,工夫片的长度也不一样,在每个工夫片中,如果工作到了过期工夫,就会被动让出线程给高优先级的工作。这部分将在第15节 scheduler&lane模型 。

两种模式函数次要执行过程

1.次要执行流程:

2.具体函数调用过程

用demo_0跟着视频调试更加清晰,黄色局部是次要工作是创立fiberRootNode和rootFiber,红色局部是创立Update,蓝色局部是调度render阶段的入口函数

3.legacy模式:

  • render调用legacyRenderSubtreeIntoContainer,最初createRootImpl会调用到createFiberRoot创立fiberRootNode,而后调用createHostRootFiber创立rootFiber,其中fiberRootNode是整个我的项目的的根节点,rootFiber是以后利用挂在的节点,也就是ReactDOM.render调用后的根节点

    //最上层的节点是整个我的项目的根节点fiberRootNodeReactDOM.render(<App />, document.getElementById("root"));//rootFiberReactDOM.render(<App />, document.getElementById("root"));//rootFiber

  • 创立完Fiber节点后,legacyRenderSubtreeIntoContainer调用updateContainer创立创立Update对象挂载到updateQueue的环形链表上,而后执行scheduleUpdateOnFiber调用performSyncWorkOnRoot进入render阶段和commit阶段

4.concurrent模式:

  • createRoot调用createRootImpl创立fiberRootNode和rootNode
  • 创立完Fiber节点后,调用ReactDOMRoot.prototype.render执行updateContainer,而后scheduleUpdateOnFiber异步调度performConcurrentWorkOnRoot进入render阶段和commit阶段

5.legacy模式次要函数正文

function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {  //...  var root = container._reactRootContainer;  var fiberRoot;  if (!root) {    // mount时    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(container, forceHydrate);//创立root节点    fiberRoot = root._internalRoot;    if (typeof callback === 'function') {//解决回调      var originalCallback = callback;      callback = function () {        var instance = getPublicRootInstance(fiberRoot);        originalCallback.call(instance);      };    }     unbatchedUpdates(function () {      updateContainer(children, fiberRoot, parentComponent, callback);//创立update入口    });  } else {    // update时    fiberRoot = root._internalRoot;    if (typeof callback === 'function') {//解决回调      var _originalCallback = callback;      callback = function () {        var instance = getPublicRootInstance(fiberRoot);        _originalCallback.call(instance);      };    }         updateContainer(children, fiberRoot, parentComponent, callback);  }}
function createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) {  var root = new FiberRootNode(containerInfo, tag, hydrate);//创立fiberRootNode  const uninitializedFiber = createHostRootFiber(tag);//创立rootFiber  //rootFiber和fiberRootNode连贯  root.current = uninitializedFiber;  uninitializedFiber.stateNode = root;  //创立updateQueue  initializeUpdateQueue(uninitializedFiber);  return root;}//对于HostRoot或者ClassComponent会应用initializeUpdateQueue创立updateQueue,而后将updateQueue挂载到fiber节点上export function initializeUpdateQueue<State>(fiber: Fiber): void {  const queue: UpdateQueue<State> = {    baseState: fiber.memoizedState,//初始state,前面会基于这个state,依据Update计算新的state    firstBaseUpdate: null,//Update造成的链表的头    lastBaseUpdate: null,//Update造成的链表的尾        //新产生的update会以单向环状链表保留在shared.pending上,计算state的时候会剪开这个环状链表,并且连贯在              //lastBaseUpdate后    shared: {      pending: null,    },    effects: null,  };  fiber.updateQueue = queue;}
function updateContainer(element, container, parentComponent, callback) {  var lane = requestUpdateLane(current$1);//获取以后可用lane 在12章解说  var update = createUpdate(eventTime, lane); //创立update  update.payload = {    element: element//jsx  };  enqueueUpdate(current$1, update);//update入队  scheduleUpdateOnFiber(current$1, lane, eventTime);//调度update  return lane;}
function scheduleUpdateOnFiber(fiber, lane, eventTime) {  if (lane === SyncLane) {//同步lane 对应legacy模式    //...    performSyncWorkOnRoot(root);//render阶段的终点 render在第6章解说  } else {//concurrent模式    //...    ensureRootIsScheduled(root, eventTime);//确保root被调度  } }

6.concurrent次要函数正文:

function ensureRootIsScheduled(root, currentTime) {  //...  var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); //计算nextLanes  //... //将lane的优先级转换成schduler的优先级  var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);  //以schedulerPriorityLevel的优先级执行performConcurrentWorkOnRoot 也就是concurrent模式的终点  newCallbackNode =       scheduleCallback(schedulerPriorityLevel,performConcurrentWorkOnRoot.bind(null, root));}

7.两种模式的不同点:

  1. createRootImpl中传入的第二个参数不一样 一个是LegacyRoot一个是ConcurrentRoot
  2. requestUpdateLane中获取的lane的优先级不同
  3. 在函数scheduleUpdateOnFiber中依据不同优先级进入不同分支,legacy模式进入performSyncWorkOnRoot,concurrent模式会异步调度performConcurrentWorkOnRoot