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

React源码6 三大核心模块之一:commit, finishConcurrentRender函数

commit阶段流程图

一、finishConcurrentRender函数

function finishConcurrentRender(root, exitStatus, lanes) {switch (exitStatus) {case RootInProgress:case RootFatalErrored:{throw new Error('Root did not complete. This is a bug in React.');}// Flow knows about invariant, so it complains if I add a break// statement, but eslint doesn't know about invariant, so it complains// if I do. eslint-disable-next-line no-fallthroughcase RootErrored:{// We should have already attempted to retry this tree. If we reached// this point, it errored again. Commit it.commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);break;}case RootSuspended:{markRootSuspended$1(root, lanes); // We have an acceptable loading state. We need to figure out if we// should immediately commit it or wait a bit.if (includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope!shouldForceFlushFallbacksInDEV()) {// This render only included retries, no updates. Throttle committing// retries so that we don't show too many loading states too quickly.var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time.if (msUntilTimeout > 10) {var nextLanes = getNextLanes(root, NoLanes);if (nextLanes !== NoLanes) {// There's additional work on this root.break;}var suspendedLanes = root.suspendedLanes;if (!isSubsetOfLanes(suspendedLanes, lanes)) {// We should prefer to render the fallback of at the last// suspended level. Ping the last suspended level to try// rendering it again.// FIXME: What if the suspended lanes are Idle? Should not restart.var eventTime = requestEventTime();markRootPinged(root, suspendedLanes);break;} // The render is suspended, it hasn't timed out, and there's no// lower priority work to do. Instead of committing the fallback// immediately, wait for more data to arrive.root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root, workInProgressRootRecoverableErrors, workInProgressTransitions), msUntilTimeout);break;}} // The work expired. Commit immediately.commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);break;}case RootSuspendedWithDelay:{markRootSuspended$1(root, lanes);if (includesOnlyTransitions(lanes)) {// This is a transition, so we should exit without committing a// placeholder and without scheduling a timeout. Delay indefinitely// until we receive more data.break;}if (!shouldForceFlushFallbacksInDEV()) {// This is not a transition, but we did trigger an avoided state.// Schedule a placeholder to display after a short delay, using the Just// Noticeable Difference.// TODO: Is the JND optimization worth the added complexity? If this is// the only reason we track the event time, then probably not.// Consider removing.var mostRecentEventTime = getMostRecentEventTime(root, lanes);var eventTimeMs = mostRecentEventTime;var timeElapsedMs = now() - eventTimeMs;var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time.if (_msUntilTimeout > 10) {// Instead of committing the fallback immediately, wait for more data// to arrive.root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root, workInProgressRootRecoverableErrors, workInProgressTransitions), _msUntilTimeout);break;}} // Commit the placeholder.commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);break;}case RootCompleted:{// The work completed. Ready to commit.commitRoot(root, workInProgressRootRecoverableErrors, workInProgressTransitions);break;}default:{throw new Error('Unknown root exit status.');}}
}

二、commitRoot函数

function commitRoot(root, recoverableErrors, transitions) {// TODO: This no longer makes any sense. We already wrap the mutation and// layout phases. Should be able to remove.var previousUpdateLanePriority = getCurrentUpdatePriority();var prevTransition = ReactCurrentBatchConfig$3.transition;try {ReactCurrentBatchConfig$3.transition = null;setCurrentUpdatePriority(DiscreteEventPriority);commitRootImpl(root, recoverableErrors, transitions, previousUpdateLanePriority);} finally {ReactCurrentBatchConfig$3.transition = prevTransition;setCurrentUpdatePriority(previousUpdateLanePriority);}return null;
}

三、commitRootImpl函数

function commitRootImpl(root, recoverableErrors, transitions, renderPriorityLevel) {do {// `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which// means `flushPassiveEffects` will sometimes result in additional// passive effects. So we need to keep flushing in a loop until there are// no more pending effects.// TODO: Might be better if `flushPassiveEffects` did not automatically// flush synchronous work at the end, to avoid factoring hazards like this.flushPassiveEffects();} while (rootWithPendingPassiveEffects !== null);flushRenderPhaseStrictModeWarningsInDEV();if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {throw new Error('Should not already be working.');}var finishedWork = root.finishedWork;var lanes = root.finishedLanes;{markCommitStarted(lanes);}if (finishedWork === null) {{markCommitStopped();}return null;} else {{if (lanes === NoLanes) {error('root.finishedLanes should not be empty during a commit. This is a ' + 'bug in React.');}}}root.finishedWork = null;root.finishedLanes = NoLanes;if (finishedWork === root.current) {throw new Error('Cannot commit the same tree as before. This error is likely caused by ' + 'a bug in React. Please file an issue.');} // commitRoot never returns a continuation; it always finishes synchronously.// So we can clear these now to allow a new callback to be scheduled.root.callbackNode = null;root.callbackPriority = NoLane; // Update the first and last pending times on this root. The new first// pending time is whatever is left on the root fiber.var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);markRootFinished(root, remainingLanes);if (root === workInProgressRoot) {// We can reset these now that they are finished.workInProgressRoot = null;workInProgress = null;workInProgressRootRenderLanes = NoLanes;} // If there are pending passive effects, schedule a callback to process them.// Do this as early as possible, so it is queued before anything else that// might get scheduled in the commit phase. (See #16714.)// TODO: Delete all other places that schedule the passive effect callback// They're redundant.if ((finishedWork.subtreeFlags & PassiveMask) !== NoFlags || (finishedWork.flags & PassiveMask) !== NoFlags) {if (!rootDoesHavePassiveEffects) {rootDoesHavePassiveEffects = true;// to store it in pendingPassiveTransitions until they get processed// We need to pass this through as an argument to commitRoot// because workInProgressTransitions might have changed between// the previous render and commit if we throttle the commit// with setTimeoutpendingPassiveTransitions = transitions;scheduleCallback$1(NormalPriority, function () {flushPassiveEffects(); // This render triggered passive effects: release the root cache pool// *after* passive effects fire to avoid freeing a cache pool that may// be referenced by a node in the tree (HostRoot, Cache boundary etc)return null;});}} // Check if there are any effects in the whole tree.// TODO: This is left over from the effect list implementation, where we had// to check for the existence of `firstEffect` to satisfy Flow. I think the// only other reason this optimization exists is because it affects profiling.// Reconsider whether this is necessary.var subtreeHasEffects = (finishedWork.subtreeFlags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;var rootHasEffect = (finishedWork.flags & (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !== NoFlags;if (subtreeHasEffects || rootHasEffect) {var prevTransition = ReactCurrentBatchConfig$3.transition;ReactCurrentBatchConfig$3.transition = null;var previousPriority = getCurrentUpdatePriority();setCurrentUpdatePriority(DiscreteEventPriority);var prevExecutionContext = executionContext;executionContext |= CommitContext; // Reset this to null before calling lifecyclesReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass// of the effect list for each phase: all mutation effects come before all// layout effects, and so on.// The first phase a "before mutation" phase. We use this phase to read the// state of the host tree right before we mutate it. This is where// getSnapshotBeforeUpdate is called.var shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(root, finishedWork);{// Mark the current commit time to be shared by all Profilers in this// batch. This enables them to be grouped later.recordCommitTime();}commitMutationEffects(root, finishedWork, lanes);resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after// the mutation phase, so that the previous tree is still current during// componentWillUnmount, but before the layout phase, so that the finished// work is current during componentDidMount/Update.root.current = finishedWork; // The next phase is the layout phase, where we call effects that read{markLayoutEffectsStarted(lanes);}commitLayoutEffects(finishedWork, root, lanes);{markLayoutEffectsStopped();}// opportunity to paint.requestPaint();executionContext = prevExecutionContext; // Reset the priority to the previous non-sync value.setCurrentUpdatePriority(previousPriority);ReactCurrentBatchConfig$3.transition = prevTransition;} else {// No effects.root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were// no effects.// TODO: Maybe there's a better way to report this.{recordCommitTime();}}var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;if (rootDoesHavePassiveEffects) {// This commit has passive effects. Stash a reference to them. But don't// schedule a callback until after flushing layout work.rootDoesHavePassiveEffects = false;rootWithPendingPassiveEffects = root;pendingPassiveEffectsLanes = lanes;} else {{nestedPassiveUpdateCount = 0;rootWithPassiveNestedUpdates = null;}} // Read this again, since an effect might have updated itremainingLanes = root.pendingLanes; // Check if there's remaining work on this root// TODO: This is part of the `componentDidCatch` implementation. Its purpose// is to detect whether something might have called setState inside// `componentDidCatch`. The mechanism is known to be flawed because `setState`// inside `componentDidCatch` is itself flawed — that's why we recommend// `getDerivedStateFromError` instead. However, it could be improved by// checking if remainingLanes includes Sync work, instead of whether there's// any work remaining at all (which would also include stuff like Suspense// retries or transitions). It's been like this for a while, though, so fixing// it probably isn't that urgent.if (remainingLanes === NoLanes) {// If there's no remaining work, we can clear the set of already failed// error boundaries.legacyErrorBoundariesThatAlreadyFailed = null;}{if (!rootDidHavePassiveEffects) {commitDoubleInvokeEffectsInDEV(root.current, false);}}onCommitRoot(finishedWork.stateNode, renderPriorityLevel);{if (isDevToolsPresent) {root.memoizedUpdaters.clear();}}{onCommitRoot$1();} // Always call this before exiting `commitRoot`, to ensure that any// additional work on this root is scheduled.ensureRootIsScheduled(root, now());if (recoverableErrors !== null) {// There were errors during this render, but recovered from them without// needing to surface it to the UI. We log them here.var onRecoverableError = root.onRecoverableError;for (var i = 0; i < recoverableErrors.length; i++) {var recoverableError = recoverableErrors[i];var componentStack = recoverableError.stack;var digest = recoverableError.digest;onRecoverableError(recoverableError.value, {componentStack: componentStack,digest: digest});}}if (hasUncaughtError) {hasUncaughtError = false;var error$1 = firstUncaughtError;firstUncaughtError = null;throw error$1;} // If the passive effects are the result of a discrete render, flush them// synchronously at the end of the current task so that the result is// immediately observable. Otherwise, we assume that they are not// order-dependent and do not need to be observed by external systems, so we// can wait until after paint.// TODO: We can optimize this by not scheduling the callback earlier. Since we// currently schedule the callback in multiple places, will wait until those// are consolidated.if (includesSomeLane(pendingPassiveEffectsLanes, SyncLane) && root.tag !== LegacyRoot) {flushPassiveEffects();} // Read this again, since a passive effect might have updated itremainingLanes = root.pendingLanes;if (includesSomeLane(remainingLanes, SyncLane)) {{markNestedUpdateScheduled();} // Count the number of times the root synchronously re-renders without// finishing. If there are too many, it indicates an infinite update loop.if (root === rootWithNestedUpdates) {nestedUpdateCount++;} else {nestedUpdateCount = 0;rootWithNestedUpdates = root;}} else {nestedUpdateCount = 0;} // If layout work was scheduled, flush it now.flushSyncCallbacks();{markCommitStopped();}return null;
}


文章转载自:
http://asp.dmyyro.cn
http://can.dmyyro.cn
http://academicals.dmyyro.cn
http://abd.dmyyro.cn
http://allegiant.dmyyro.cn
http://brains.dmyyro.cn
http://anoxemia.dmyyro.cn
http://australopithecus.dmyyro.cn
http://bluffly.dmyyro.cn
http://beguine.dmyyro.cn
http://cellularity.dmyyro.cn
http://auditorship.dmyyro.cn
http://babesia.dmyyro.cn
http://aquiline.dmyyro.cn
http://cgt.dmyyro.cn
http://buff.dmyyro.cn
http://chemoprophylactic.dmyyro.cn
http://cataplasia.dmyyro.cn
http://cardines.dmyyro.cn
http://artisanry.dmyyro.cn
http://automonitor.dmyyro.cn
http://apace.dmyyro.cn
http://cavalryman.dmyyro.cn
http://ceramide.dmyyro.cn
http://barcarolle.dmyyro.cn
http://baldheaded.dmyyro.cn
http://bicho.dmyyro.cn
http://axile.dmyyro.cn
http://beseeching.dmyyro.cn
http://abraxas.dmyyro.cn
http://www.dtcms.com/a/280630.html

相关文章:

  • 前端学习笔记:React.js中state和props的区别和联系
  • haproxy负载均衡
  • AntV G6 基础元素详解(React版)
  • 【PTA数据结构 | C语言版】创建哈夫曼树
  • 使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第二十一讲)
  • 【PDF识别改名】使用京东云OCR完成PDF图片识别改名,根据PDF图片内容批量改名详细步骤和解决方案
  • 同样是“跳转”,为何forward地址栏不变,redirect会变?
  • RNN、GRU 与 LSTM 计算成本深入对比
  • 基于光场相机的激光增材制造熔池温度场原位多眼监测​​
  • 【zynq7020】PL的“Hello LED”
  • FPGA高端图像ISP培训课程,提供工程源码+视频教程+FPGA开发板
  • Softhub软件下载站实战开发(十八):软件分类展示
  • 使用LNMP一键安装包安装PHP、Nginx、Redis、Swoole、OPcache
  • Vmware中安装的CentOS7如何扩展硬盘大小
  • 语言模型玩转3D生成:LLaMA-Mesh开源项目
  • 【鸿蒙HarmonyOS】鸿蒙app开发入门到实战教程(二):封装自定义可复用组件
  • 前端面试专栏-工程化:25.项目亮点与技术难点梳理
  • 手搓RAG
  • 知识增强型Agent开发新范式:基于ERNIE-4.5的检索增强生成架构实践
  • 力扣-使用双指针的方法的题们(持续更新中。。。
  • NipaPlay(视频播放器) v1.3.24 绿色版
  • ubuntu22.04谷歌浏览器中文输入法bug
  • 非实时的防控场景
  • 其他常见 HTTP 方法
  • redisson 设置了过期时间,会自动续期吗
  • 论文略读:QM-ARC: QoS-aware Multi-tier Adaptive Cache Replacement Strategy
  • 2025华为ODB卷-任务总执行时长-三语言题解
  • 图灵在二战期间是如何破译德国军用密码的?
  • 虚拟主机CPU占用100导致打不开的一次处理
  • 网络基础协议综合实验