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.两种模式的不同点:
- createRootImpl中传入的第二个参数不一样 一个是LegacyRoot一个是ConcurrentRoot
- requestUpdateLane中获取的lane的优先级不同
- 在函数scheduleUpdateOnFiber中依据不同优先级进入不同分支,legacy模式进入performSyncWorkOnRoot,concurrent模式会异步调度performConcurrentWorkOnRoot