( root: FiberRoot, lanes: Lanes, forceSync: boolean, )
| 1064 | } |
| 1065 | |
| 1066 | export function performWorkOnRoot( |
| 1067 | root: FiberRoot, |
| 1068 | lanes: Lanes, |
| 1069 | forceSync: boolean, |
| 1070 | ): void { |
| 1071 | if ((executionContext & (RenderContext | CommitContext)) !== NoContext) { |
| 1072 | throw new Error('Should not already be working.'); |
| 1073 | } |
| 1074 | |
| 1075 | if (enableProfilerTimer && enableComponentPerformanceTrack) { |
| 1076 | if (workInProgressRootRenderLanes !== NoLanes && workInProgress !== null) { |
| 1077 | const yieldedFiber = workInProgress; |
| 1078 | // We've returned from yielding to the event loop. Let's log the time it took. |
| 1079 | const yieldEndTime = now(); |
| 1080 | switch (yieldReason) { |
| 1081 | case SuspendedOnImmediate: |
| 1082 | case SuspendedOnData: |
| 1083 | logSuspendedYieldTime(yieldStartTime, yieldEndTime, yieldedFiber); |
| 1084 | break; |
| 1085 | case SuspendedOnAction: |
| 1086 | logActionYieldTime(yieldStartTime, yieldEndTime, yieldedFiber); |
| 1087 | break; |
| 1088 | default: |
| 1089 | logYieldTime(yieldStartTime, yieldEndTime); |
| 1090 | } |
| 1091 | } |
| 1092 | } |
| 1093 | |
| 1094 | // We disable time-slicing in some cases: if the work has been CPU-bound |
| 1095 | // for too long ("expired" work, to prevent starvation), or we're in |
| 1096 | // sync-updates-by-default mode. |
| 1097 | const shouldTimeSlice = |
| 1098 | (!forceSync && |
| 1099 | !includesBlockingLane(lanes) && |
| 1100 | !includesExpiredLane(root, lanes)) || |
| 1101 | // If we're prerendering, then we should use the concurrent work loop |
| 1102 | // even if the lanes are synchronous, so that prerendering never blocks |
| 1103 | // the main thread. |
| 1104 | // TODO: We should consider doing this whenever a sync lane is suspended, |
| 1105 | // even for regular pings. |
| 1106 | checkIfRootIsPrerendering(root, lanes); |
| 1107 | |
| 1108 | let exitStatus: RootExitStatus = shouldTimeSlice |
| 1109 | ? renderRootConcurrent(root, lanes) |
| 1110 | : renderRootSync(root, lanes, true); |
| 1111 | |
| 1112 | let renderWasConcurrent = shouldTimeSlice; |
| 1113 | |
| 1114 | do { |
| 1115 | if (exitStatus === RootInProgress) { |
| 1116 | // Render phase is still in progress. |
| 1117 | if (workInProgressRootIsPrerendering && !shouldTimeSlice) { |
| 1118 | // We're in prerendering mode, but time slicing is not enabled. This |
| 1119 | // happens when something suspends during a synchronous update. Exit the |
| 1120 | // the work loop. When we resume, we'll use the concurrent work loop so |
| 1121 | // that prerendering is non-blocking. |
| 1122 | // |
| 1123 | // Mark the root as suspended. Usually we do this at the end of the |
no test coverage detected