当前位置: 首页 > news >正文

React源码5 三大核心模块之一:render,renderRoot

 render阶段流程图

一、renderRootSync函数

function renderRootSync(root, lanes) {var prevExecutionContext = executionContext;executionContext |= RenderContext;var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack// and prepare a fresh one. Otherwise we'll continue where we left off.if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {{if (isDevToolsPresent) {var memoizedUpdaters = root.memoizedUpdaters;if (memoizedUpdaters.size > 0) {restorePendingUpdaters(root, workInProgressRootRenderLanes);memoizedUpdaters.clear();} // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.// If we bailout on this work, we'll move them back (like above).// It's important to move them now in case the work spawns more work at the same priority with different updaters.// That way we can keep the current update and future updates separate.movePendingFibersToMemoized(root, lanes);}}workInProgressTransitions = getTransitionsForLanes();prepareFreshStack(root, lanes);}{markRenderStarted(lanes);}do {try {workLoopSync();break;} catch (thrownValue) {handleError(root, thrownValue);}} while (true);resetContextDependencies();executionContext = prevExecutionContext;popDispatcher(prevDispatcher);if (workInProgress !== null) {// This is a sync render, so we should have finished the whole tree.throw new Error('Cannot commit an incomplete root. This error is likely caused by a ' + 'bug in React. Please file an issue.');}{markRenderStopped();} // Set this to null to indicate there's no in-progress render.workInProgressRoot = null;workInProgressRootRenderLanes = NoLanes;return workInProgressRootExitStatus;
} // The work loop is an extremely hot path. Tell Closure not to inline it./** @noinline */function workLoopSync() {// Already timed out, so perform work without checking if we need to yield.while (workInProgress !== null) {performUnitOfWork(workInProgress);}
}

二、renderRootConcurrent函数

function renderRootConcurrent(root, lanes) {  var prevExecutionContext = executionContext;executionContext |= RenderContext;var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack// and prepare a fresh one. Otherwise we'll continue where we left off.if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {{if (isDevToolsPresent) {var memoizedUpdaters = root.memoizedUpdaters;if (memoizedUpdaters.size > 0) {restorePendingUpdaters(root, workInProgressRootRenderLanes);memoizedUpdaters.clear();} // At this point, move Fibers that scheduled the upcoming work from the Map to the Set.// If we bailout on this work, we'll move them back (like above).// It's important to move them now in case the work spawns more work at the same priority with different updaters.// That way we can keep the current update and future updates separate.movePendingFibersToMemoized(root, lanes);}}workInProgressTransitions = getTransitionsForLanes();resetRenderTimer();prepareFreshStack(root, lanes);}{markRenderStarted(lanes);}do {try {workLoopConcurrent();break;} catch (thrownValue) {handleError(root, thrownValue);}} while (true);resetContextDependencies();popDispatcher(prevDispatcher);executionContext = prevExecutionContext;if (workInProgress !== null) {// Still work remaining.{markRenderYielded();}return RootInProgress;} else {// Completed the tree.{markRenderStopped();} // Set this to null to indicate there's no in-progress render.workInProgressRoot = null;workInProgressRootRenderLanes = NoLanes; // Return the final exit status.return workInProgressRootExitStatus;}
}

三、workLoopSync函数

function workLoopSync() {// Already timed out, so perform work without checking if we need to yield.while (workInProgress !== null) {performUnitOfWork(workInProgress);}
}

四、workLoopConcurrent函数

function workLoopConcurrent() {// Perform work until Scheduler asks us to yieldwhile (workInProgress !== null && !shouldYield()) {performUnitOfWork(workInProgress);}
}

五、performUnitOfWork函数

function performUnitOfWork(unitOfWork) {// The current, flushed, state of this fiber is the alternate. Ideally// nothing should rely on this, but relying on it here means that we don't// need an additional field on the work in progress.var current = unitOfWork.alternate;setCurrentFiber(unitOfWork);var next;if ( (unitOfWork.mode & ProfileMode) !== NoMode) {startProfilerTimer(unitOfWork);next = beginWork$1(current, unitOfWork, subtreeRenderLanes);stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);} else {next = beginWork$1(current, unitOfWork, subtreeRenderLanes);}resetCurrentFiber();unitOfWork.memoizedProps = unitOfWork.pendingProps;if (next === null) {// If this doesn't spawn new work, complete the current work.completeUnitOfWork(unitOfWork);} else {workInProgress = next;}ReactCurrentOwner$2.current = null;
}

六、beginWork函数

function beginWork(current, workInProgress, renderLanes) {{if (workInProgress._debugNeedsRemount && current !== null) {// This will restart the begin phase with a new fiber.return remountFiber(current, workInProgress, createFiberFromTypeAndProps(workInProgress.type, workInProgress.key, workInProgress.pendingProps, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.lanes));}}if (current !== null) {var oldProps = current.memoizedProps;var newProps = workInProgress.pendingProps;if (oldProps !== newProps || hasContextChanged() || ( // Force a re-render if the implementation changed due to hot reload:workInProgress.type !== current.type )) {// If props or context changed, mark the fiber as having performed work.// This may be unset if the props are determined to be equal later (memo).didReceiveUpdate = true;} else {// Neither props nor legacy context changes. Check if there's a pending// update or context change.var hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(current, renderLanes);if (!hasScheduledUpdateOrContext && // If this is the second pass of an error or suspense boundary, there// may not be work scheduled on `current`, so we check for this flag.(workInProgress.flags & DidCapture) === NoFlags) {// No pending updates or context. Bail out now.didReceiveUpdate = false;return attemptEarlyBailoutIfNoScheduledUpdate(current, workInProgress, renderLanes);}if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {// This is a special case that only exists for legacy mode.// See https://github.com/facebook/react/pull/19216.didReceiveUpdate = true;} else {// An update was scheduled on this fiber, but there are no new props// nor legacy context. Set this to false. If an update queue or context// consumer produces a changed value, it will set this to true. Otherwise,// the component will assume the children have not changed and bail out.didReceiveUpdate = false;}}} else {didReceiveUpdate = false;if (getIsHydrating() && isForkedChild(workInProgress)) {// Check if this child belongs to a list of muliple children in// its parent.//// In a true multi-threaded implementation, we would render children on// parallel threads. This would represent the beginning of a new render// thread for this subtree.//// We only use this for id generation during hydration, which is why the// logic is located in this special branch.var slotIndex = workInProgress.index;var numberOfForks = getForksAtLevel();pushTreeId(workInProgress, numberOfForks, slotIndex);}} // Before entering the begin phase, clear pending update priority.// TODO: This assumes that we're about to evaluate the component and process// the update queue. However, there's an exception: SimpleMemoComponent// sometimes bails out later in the begin phase. This indicates that we should// move this assignment out of the common path and into each branch.workInProgress.lanes = NoLanes;switch (workInProgress.tag) {case IndeterminateComponent:{return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderLanes);}case LazyComponent:{var elementType = workInProgress.elementType;return mountLazyComponent(current, workInProgress, elementType, renderLanes);}case FunctionComponent:{var Component = workInProgress.type;var unresolvedProps = workInProgress.pendingProps;var resolvedProps = workInProgress.elementType === Component ? unresolvedProps : resolveDefaultProps(Component, unresolvedProps);return updateFunctionComponent(current, workInProgress, Component, resolvedProps, renderLanes);}case ClassComponent:{var _Component = workInProgress.type;var _unresolvedProps = workInProgress.pendingProps;var _resolvedProps = workInProgress.elementType === _Component ? _unresolvedProps : resolveDefaultProps(_Component, _unresolvedProps);return updateClassComponent(current, workInProgress, _Component, _resolvedProps, renderLanes);}case HostRoot:return updateHostRoot(current, workInProgress, renderLanes);case HostComponent:return updateHostComponent(current, workInProgress, renderLanes);case HostText:return updateHostText(current, workInProgress);case SuspenseComponent:return updateSuspenseComponent(current, workInProgress, renderLanes);case HostPortal:return updatePortalComponent(current, workInProgress, renderLanes);case ForwardRef:{var type = workInProgress.type;var _unresolvedProps2 = workInProgress.pendingProps;var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);return updateForwardRef(current, workInProgress, type, _resolvedProps2, renderLanes);}case Fragment:return updateFragment(current, workInProgress, renderLanes);case Mode:return updateMode(current, workInProgress, renderLanes);case Profiler:return updateProfiler(current, workInProgress, renderLanes);case ContextProvider:return updateContextProvider(current, workInProgress, renderLanes);case ContextConsumer:return updateContextConsumer(current, workInProgress, renderLanes);case MemoComponent:{var _type2 = workInProgress.type;var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props.var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3);{if (workInProgress.type !== workInProgress.elementType) {var outerPropTypes = _type2.propTypes;if (outerPropTypes) {checkPropTypes(outerPropTypes, _resolvedProps3, // Resolved for outer only'prop', getComponentNameFromType(_type2));}}}_resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3);return updateMemoComponent(current, workInProgress, _type2, _resolvedProps3, renderLanes);}case SimpleMemoComponent:{return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, renderLanes);}case IncompleteClassComponent:{var _Component2 = workInProgress.type;var _unresolvedProps4 = workInProgress.pendingProps;var _resolvedProps4 = workInProgress.elementType === _Component2 ? _unresolvedProps4 : resolveDefaultProps(_Component2, _unresolvedProps4);return mountIncompleteClassComponent(current, workInProgress, _Component2, _resolvedProps4, renderLanes);}case SuspenseListComponent:{return updateSuspenseListComponent(current, workInProgress, renderLanes);}case ScopeComponent:{break;}case OffscreenComponent:{return updateOffscreenComponent(current, workInProgress, renderLanes);}}throw new Error("Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in " + 'React. Please file an issue.');
}

七、completeUnitOfwork函数

function completeUnitOfWork(unitOfWork) {// Attempt to complete the current unit of work, then move to the next// sibling. If there are no more siblings, return to the parent fiber.var completedWork = unitOfWork;do {// The current, flushed, state of this fiber is the alternate. Ideally// nothing should rely on this, but relying on it here means that we don't// need an additional field on the work in progress.var current = completedWork.alternate;var returnFiber = completedWork.return; // Check if the work completed or if something threw.if ((completedWork.flags & Incomplete) === NoFlags) {setCurrentFiber(completedWork);var next = void 0;if ( (completedWork.mode & ProfileMode) === NoMode) {next = completeWork(current, completedWork, subtreeRenderLanes);} else {startProfilerTimer(completedWork);next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);}resetCurrentFiber();if (next !== null) {// Completing this fiber spawned new work. Work on that next.workInProgress = next;return;}} else {// This fiber did not complete because something threw. Pop values off// the stack without entering the complete phase. If this is a boundary,// capture values if possible.var _next = unwindWork(current, completedWork); // Because this fiber did not complete, don't reset its lanes.if (_next !== null) {// If completing this work spawned new work, do that next. We'll come// back here again.// Since we're restarting, remove anything that is not a host effect// from the effect tag._next.flags &= HostEffectMask;workInProgress = _next;return;}if ( (completedWork.mode & ProfileMode) !== NoMode) {// Record the render duration for the fiber that errored.stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.var actualDuration = completedWork.actualDuration;var child = completedWork.child;while (child !== null) {actualDuration += child.actualDuration;child = child.sibling;}completedWork.actualDuration = actualDuration;}if (returnFiber !== null) {// Mark the parent fiber as incomplete and clear its subtree flags.returnFiber.flags |= Incomplete;returnFiber.subtreeFlags = NoFlags;returnFiber.deletions = null;} else {// We've unwound all the way to the root.workInProgressRootExitStatus = RootDidNotComplete;workInProgress = null;return;}}var siblingFiber = completedWork.sibling;if (siblingFiber !== null) {// If there is more work to do in this returnFiber, do that next.workInProgress = siblingFiber;return;} // Otherwise, return to the parentcompletedWork = returnFiber; // Update the next thing we're working on in case something throws.workInProgress = completedWork;} while (completedWork !== null); // We've reached the root.if (workInProgressRootExitStatus === RootInProgress) {workInProgressRootExitStatus = RootCompleted;}
}

http://www.xdnf.cn/news/1127575.html

相关文章:

  • docker-compose 配置启动2个MongoDB
  • 【Docker基础】Dockerfile构建与运行流程完全指南:从原理到实践优化
  • PostgreSQL 超详细安装与使用教程:从入门到实战
  • Axios 和Express 区别对比
  • 使用LNMP一键安装包安装PHP、Nginx、Redis、Swoole、OPcache
  • Linux系统调优和工具
  • 理解 HTTP POST 请求中的 json 和 data 参数
  • 【目标追踪】MUTR3D: A Multi-camera Tracking Framework via 3D-to-2D Queries
  • 快速了解 HTTPS
  • 【BUG处理】构建APK时遇到错误:‘flutter‘ 命令未被识别。这通常表示您的系统中未安装Flutter SDK或环境变量配置不正确。
  • 【亲测有效】ubuntu20.04服务器新建用户+vnc配置教程
  • 基于按键开源MultiButton框架深入理解代码框架(二)(指针的深入理解与应用)
  • 【橘子分布式】Thrift RPC(编程篇)
  • OMPL安装问题:CMake报错找不到ompl依赖
  • Linux探秘坊-------14.信号
  • Axios 完整功能介绍和完整示例演示
  • OSPFv3中LSA参数
  • 【Luogu】每日一题——Day3. P6392 中意 (数学 取模)
  • 【深度学习优化算法】06:动量法
  • Sentinel热点参数限流完整示例实现
  • 高温车间(60℃+)如何选高温/宽温边缘网关设备?
  • 如何把手机ip地址切换到外省
  • Datawhale 25年7月组队学习coze-ai-assistant Task1学习笔记:动手实践第一个AI Agent—英伦生活口语陪练精灵
  • 学习C++、QT---26(QT中实现记事本项目实现文件路径的提示、现在我们来学习一下C++类模板、记事本的行高亮的操作的讲解)
  • etcd自动压缩清理
  • QT——QComboBox组合框控件
  • Flink实战项目——城市交通实时监控平台
  • 函数柯里化详解
  • Luban配置教程
  • 如何在simulink中怎么获取足端轨迹代码解释?