How to use renderRootConcurrent method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberWorkLoop.new.js

Source:ReactFiberWorkLoop.new.js Github

copy

Full Screen

...670 }671 // 去执行更新任务的工作循环,一旦超出时间片,则会退出renderRootConcurrent672 // 去执行下面的逻辑673 // 3. 构造fiber树674 let exitStatus = renderRootConcurrent(root, lanes);675 if (676 includesSomeLane(677 workInProgressRootIncludedLanes,678 workInProgressRootUpdatedLanes,679 )680 ) {681 // The render included lanes that were updated during the render phase.682 // For example, when unhiding a hidden tree, we include all the lanes683 // that were previously skipped when the tree was hidden. That set of684 // lanes is a superset of the lanes we started rendering with.685 //686 // So we'll throw out the current work and restart.687 // 如果在render过程中产生了新的update, 且新update的优先级与最初render的优先级有交集688 // 那么最初render无效, 丢弃最初render的结果, 等待下一次调度689 prepareFreshStack(root, NoLanes);690 } else if (exitStatus !== RootIncomplete) {691 // 4. 异常处理: 有可能fiber构造过程中出现异常692 if (exitStatus === RootErrored) {693 executionContext |= RetryAfterError;694 // If an error occurred during hydration,695 // discard server response and fall back to client side render.696 if (root.hydrate) {697 root.hydrate = false;698 clearContainer(root.containerInfo);699 }700 // If something threw an error, try rendering one more time. We'll render701 // synchronously to block concurrent data mutations, and we'll includes702 // all pending updates are included. If it still fails after the second703 // attempt, we'll give up and commit the resulting tree.704 lanes = getLanesToRetrySynchronouslyOnError(root);705 if (lanes !== NoLanes) {706 exitStatus = renderRootSync(root, lanes);707 }708 }709 if (exitStatus === RootFatalErrored) {710 const fatalError = workInProgressRootFatalError;711 prepareFreshStack(root, NoLanes);712 markRootSuspended(root, lanes);713 ensureRootIsScheduled(root, now());714 throw fatalError;715 }716 // We now have a consistent tree. The next step is either to commit it,717 // or, if something suspended, wait to commit it after a timeout.718 const finishedWork: Fiber = (root.current.alternate: any);719 root.finishedWork = finishedWork;720 root.finishedLanes = lanes;721 // 5. 输出: 渲染fiber树722 finishConcurrentRender(root, exitStatus, lanes);723 }724 // 调用ensureRootIsScheduled去检查有无过期任务,是否需要调度过期任务725 ensureRootIsScheduled(root, now());726 // 更新任务未完成,return自己,方便Scheduler判断任务完成状态727 if (root.callbackNode === originalCallbackNode) {728 // The task node scheduled for this root is the same one that's729 // currently executed. Need to return a continuation.730 return performConcurrentWorkOnRoot.bind(null, root);731 }732 enableLog && console.log('performConcurrentWorkOnRoot end')733 // 否则retutn null,表示任务已经完成,通知Scheduler停止调度734 return null;735}736function finishConcurrentRender(root, exitStatus, lanes) {737 switch (exitStatus) {738 case RootIncomplete:739 case RootFatalErrored: {740 invariant(false, 'Root did not complete. This is a bug in React.');741 }742 // Flow knows about invariant, so it complains if I add a break743 // statement, but eslint doesn't know about invariant, so it complains744 // if I do. eslint-disable-next-line no-fallthrough745 case RootErrored: {746 // We should have already attempted to retry this tree. If we reached747 // this point, it errored again. Commit it.748 commitRoot(root);749 break;750 }751 case RootSuspended: {752 markRootSuspended(root, lanes);753 // We have an acceptable loading state. We need to figure out if we754 // should immediately commit it or wait a bit.755 if (756 includesOnlyRetries(lanes)757 ) {758 // This render only included retries, no updates. Throttle committing759 // retries so that we don't show too many loading states too quickly.760 const msUntilTimeout =761 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();762 // Don't bother with a very short suspense time.763 if (msUntilTimeout > 10) {764 const nextLanes = getNextLanes(root, NoLanes);765 if (nextLanes !== NoLanes) {766 // There's additional work on this root.767 break;768 }769 const suspendedLanes = root.suspendedLanes;770 if (!isSubsetOfLanes(suspendedLanes, lanes)) {771 // We should prefer to render the fallback of at the last772 // suspended level. Ping the last suspended level to try773 // rendering it again.774 // FIXME: What if the suspended lanes are Idle? Should not restart.775 const eventTime = requestEventTime();776 markRootPinged(root, suspendedLanes, eventTime);777 break;778 }779 // The render is suspended, it hasn't timed out, and there's no780 // lower priority work to do. Instead of committing the fallback781 // immediately, wait for more data to arrive.782 root.timeoutHandle = scheduleTimeout(783 commitRoot.bind(null, root),784 msUntilTimeout,785 );786 break;787 }788 }789 // The work expired. Commit immediately.790 commitRoot(root);791 break;792 }793 case RootSuspendedWithDelay: {794 markRootSuspended(root, lanes);795 if (includesOnlyTransitions(lanes)) {796 // This is a transition, so we should exit without committing a797 // placeholder and without scheduling a timeout. Delay indefinitely798 // until we receive more data.799 break;800 }801 // This is not a transition, but we did trigger an avoided state.802 // Schedule a placeholder to display after a short delay, using the Just803 // Noticeable Difference.804 // TODO: Is the JND optimization worth the added complexity? If this is805 // the only reason we track the event time, then probably not.806 // Consider removing.807 const mostRecentEventTime = getMostRecentEventTime(root, lanes);808 const eventTimeMs = mostRecentEventTime;809 const timeElapsedMs = now() - eventTimeMs;810 const msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs;811 // Don't bother with a very short suspense time.812 if (msUntilTimeout > 10) {813 // Instead of committing the fallback immediately, wait for more data814 // to arrive.815 root.timeoutHandle = scheduleTimeout(816 commitRoot.bind(null, root),817 msUntilTimeout,818 );819 break;820 }821 // Commit the placeholder.822 commitRoot(root);823 break;824 }825 case RootCompleted: {826 // The work completed. Ready to commit.827 commitRoot(root);828 break;829 }830 default: {831 invariant(false, 'Unknown root exit status.');832 }833 }834}835function markRootSuspended(root, suspendedLanes) {836 // When suspending, we should always exclude lanes that were pinged or (more837 // rarely, since we try to avoid it) updated during the render phase.838 // TODO: Lol maybe there's a better way to factor this besides this839 // obnoxiously named function :)840 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);841 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);842 markRootSuspended_dontCallThisOneDirectly(root, suspendedLanes);843}844// This is the entry point for synchronous tasks that don't go845// through Scheduler846function performSyncWorkOnRoot(root) {847 invariant(848 (executionContext & (RenderContext | CommitContext)) === NoContext,849 'Should not already be working.',850 );851 852 console.log('ReactFiberWorkLoop.new: performSyncWorkOnRoot')853 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('performSyncWorkOnRoot')) debugger854 flushPassiveEffects();855 let lanes;856 let exitStatus;857 if (858 root === workInProgressRoot &&859 includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)860 ) {861 // There's a partial tree, and at least one of its lanes has expired. Finish862 // rendering it before rendering the rest of the expired work.863 lanes = workInProgressRootRenderLanes;864 exitStatus = renderRootSync(root, lanes);865 if (866 includesSomeLane(867 workInProgressRootIncludedLanes,868 workInProgressRootUpdatedLanes,869 )870 ) {871 // The render included lanes that were updated during the render phase.872 // For example, when unhiding a hidden tree, we include all the lanes873 // that were previously skipped when the tree was hidden. That set of874 // lanes is a superset of the lanes we started rendering with.875 //876 // Note that this only happens when part of the tree is rendered877 // concurrently. If the whole tree is rendered synchronously, then there878 // are no interleaved events.879 lanes = getNextLanes(root, lanes);880 exitStatus = renderRootSync(root, lanes);881 }882 } else {883 lanes = getNextLanes(root, NoLanes);884 exitStatus = renderRootSync(root, lanes);885 }886 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {887 executionContext |= RetryAfterError;888 // If an error occurred during hydration,889 // discard server response and fall back to client side render.890 if (root.hydrate) {891 root.hydrate = false;892 clearContainer(root.containerInfo);893 }894 // If something threw an error, try rendering one more time. We'll render895 // synchronously to block concurrent data mutations, and we'll includes896 // all pending updates are included. If it still fails after the second897 // attempt, we'll give up and commit the resulting tree.898 lanes = getLanesToRetrySynchronouslyOnError(root);899 if (lanes !== NoLanes) {900 exitStatus = renderRootSync(root, lanes);901 }902 }903 if (exitStatus === RootFatalErrored) {904 const fatalError = workInProgressRootFatalError;905 prepareFreshStack(root, NoLanes);906 markRootSuspended(root, lanes);907 ensureRootIsScheduled(root, now());908 throw fatalError;909 }910 // We now have a consistent tree. Because this is a sync render, we911 // will commit it even if something suspended.912 const finishedWork: Fiber = (root.current.alternate: any);913 root.finishedWork = finishedWork;914 root.finishedLanes = lanes;915 commitRoot(root);916 // Before exiting, make sure there's a callback scheduled for the next917 // pending level.918 ensureRootIsScheduled(root, now());919 return null;920}921export function flushRoot(root: FiberRoot, lanes: Lanes) {922 markRootExpired(root, lanes);923 ensureRootIsScheduled(root, now());924 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {925 resetRenderTimer();926 flushSyncCallbackQueue();927 }928}929export function getExecutionContext(): ExecutionContext {930 return executionContext;931}932export function flushDiscreteUpdates() {933 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.934 // However, `act` uses `batchedUpdates`, so there's no way to distinguish935 // those two cases. Need to fix this before exposing flushDiscreteUpdates936 // as a public API.937 if (938 (executionContext & (BatchedContext | RenderContext | CommitContext)) !==939 NoContext940 ) {941 // We're already rendering, so we can't synchronously flush pending work.942 // This is probably a nested event dispatch triggered by a lifecycle/effect,943 // like `el.focus()`. Exit.944 return;945 }946 flushPendingDiscreteUpdates();947 // If the discrete updates scheduled passive effects, flush them now so that948 // they fire before the next serial event.949 flushPassiveEffects();950}951export function deferredUpdates<A>(fn: () => A): A {952 return runWithPriority(NormalSchedulerPriority, fn);953}954function flushPendingDiscreteUpdates() {955 if (rootsWithPendingDiscreteUpdates !== null) {956 // For each root with pending discrete updates, schedule a callback to957 // immediately flush them.958 const roots = rootsWithPendingDiscreteUpdates;959 rootsWithPendingDiscreteUpdates = null;960 roots.forEach(root => {961 markDiscreteUpdatesExpired(root);962 ensureRootIsScheduled(root, now());963 });964 }965 // Now flush the immediate queue.966 flushSyncCallbackQueue();967}968export function batchedUpdates<A, R>(fn: A => R, a: A): R {969 const prevExecutionContext = executionContext;970 executionContext |= BatchedContext;971 try {972 return fn(a);973 } finally {974 executionContext = prevExecutionContext;975 if (executionContext === NoContext) {976 // Flush the immediate callbacks that were scheduled during this batch977 resetRenderTimer();978 flushSyncCallbackQueue();979 }980 }981}982export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {983 const prevExecutionContext = executionContext;984 // 所有的事件在触发的时候,都会先调用 batchedEventUpdates 这个方法985 // 在这里就会修改 executionContext 的值,React 就知道此时的 setState 在自己的掌控中986 executionContext |= EventContext;987 try {988 return fn(a);989 } finally {990 executionContext = prevExecutionContext;991 // 调用结束后,调用 flushSyncCallbackQueue992 if (executionContext === NoContext) {993 // Flush the immediate callbacks that were scheduled during this batch994 resetRenderTimer();995 flushSyncCallbackQueue();996 }997 }998}999export function discreteUpdates<A, B, C, D, R>(1000 fn: (A, B, C) => R,1001 a: A,1002 b: B,1003 c: C,1004 d: D,1005): R {1006 const prevExecutionContext = executionContext;1007 executionContext |= DiscreteEventContext;1008 try {1009 return runWithPriority(1010 UserBlockingSchedulerPriority,1011 fn.bind(null, a, b, c, d),1012 );1013 } finally {1014 executionContext = prevExecutionContext;1015 if (executionContext === NoContext) {1016 // Flush the immediate callbacks that were scheduled during this batch1017 resetRenderTimer();1018 flushSyncCallbackQueue();1019 }1020 }1021}1022export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1023 const prevExecutionContext = executionContext;1024 executionContext &= ~BatchedContext;1025 executionContext |= LegacyUnbatchedContext;1026 try {1027 return fn(a);1028 } finally {1029 executionContext = prevExecutionContext;1030 if (executionContext === NoContext) {1031 // Flush the immediate callbacks that were scheduled during this batch1032 resetRenderTimer();1033 flushSyncCallbackQueue();1034 }1035 }1036}1037export function flushSync<A, R>(fn: A => R, a: A): R {1038 const prevExecutionContext = executionContext;1039 if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {1040 return fn(a);1041 }1042 executionContext |= BatchedContext;1043 try {1044 if (fn) {1045 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));1046 } else {1047 return (undefined: $FlowFixMe);1048 }1049 } finally {1050 executionContext = prevExecutionContext;1051 // Flush the immediate callbacks that were scheduled during this batch.1052 // Note that this will happen even if batchedUpdates is higher up1053 // the stack.1054 flushSyncCallbackQueue();1055 }1056}1057export function flushControlled(fn: () => mixed): void {1058 const prevExecutionContext = executionContext;1059 executionContext |= BatchedContext;1060 try {1061 runWithPriority(ImmediateSchedulerPriority, fn);1062 } finally {1063 executionContext = prevExecutionContext;1064 if (executionContext === NoContext) {1065 // Flush the immediate callbacks that were scheduled during this batch1066 resetRenderTimer();1067 flushSyncCallbackQueue();1068 }1069 }1070}1071export function pushRenderLanes(fiber: Fiber, lanes: Lanes) {1072 pushToStack(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);1073 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);1074 workInProgressRootIncludedLanes = mergeLanes(1075 workInProgressRootIncludedLanes,1076 lanes,1077 );1078}1079export function popRenderLanes(fiber: Fiber) {1080 subtreeRenderLanes = subtreeRenderLanesCursor.current;1081 popFromStack(subtreeRenderLanesCursor, fiber);1082}1083/**1084刷新栈帧: 重置 FiberRoot上的全局属性 和 `fiber树构造`循环过程中的全局变量1085*/1086function prepareFreshStack(root: FiberRoot, lanes: Lanes) {1087 // workInProgressRoot第一次在这里初始化1088 enableLog && console.log('prepareFreshStack start')1089 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('prepareFreshStack')) debugger1090 1091 root.finishedWork = null;1092 root.finishedLanes = NoLanes;1093 const timeoutHandle = root.timeoutHandle;1094 if (timeoutHandle !== noTimeout) { // noTimeout === -11095 // The root previous suspended and scheduled a timeout to commit a fallback1096 // state. Now that we have additional work, cancel the timeout.1097 root.timeoutHandle = noTimeout;1098 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1099 cancelTimeout(timeoutHandle);1100 }1101 if (workInProgress !== null) {1102 let interruptedWork = workInProgress.return;1103 while (interruptedWork !== null) {1104 unwindInterruptedWork(interruptedWork);1105 interruptedWork = interruptedWork.return;1106 }1107 }1108 workInProgressRoot = root;1109 workInProgress = createWorkInProgress(root.current, null);1110 workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;1111 workInProgressRootExitStatus = RootIncomplete;1112 workInProgressRootFatalError = null;1113 workInProgressRootSkippedLanes = NoLanes;1114 workInProgressRootUpdatedLanes = NoLanes;1115 workInProgressRootPingedLanes = NoLanes;1116 if (enableSchedulerTracing) {1117 spawnedWorkDuringRender = null;1118 }1119 enableLog && console.log('prepareFreshStack end')1120}1121function handleError(root, thrownValue): void {1122 do {1123 let erroredWork = workInProgress;1124 try {1125 // Reset module-level state that was set during the render phase.1126 resetContextDependencies();1127 resetHooksAfterThrow();1128 // TODO: I found and added this missing line while investigating a1129 // separate issue. Write a regression test using string refs.1130 ReactCurrentOwner.current = null;1131 if (erroredWork === null || erroredWork.return === null) {1132 // Expected to be working on a non-root fiber. This is a fatal error1133 // because there's no ancestor that can handle it; the root is1134 // supposed to capture all errors that weren't caught by an error1135 // boundary.1136 workInProgressRootExitStatus = RootFatalErrored;1137 workInProgressRootFatalError = thrownValue;1138 // Set `workInProgress` to null. This represents advancing to the next1139 // sibling, or the parent if there are no siblings. But since the root1140 // has no siblings nor a parent, we set it to null. Usually this is1141 // handled by `completeUnitOfWork` or `unwindWork`, but since we're1142 // intentionally not calling those, we need set it here.1143 // TODO: Consider calling `unwindWork` to pop the contexts.1144 workInProgress = null;1145 return;1146 }1147 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {1148 // Record the time spent rendering before an error was thrown. This1149 // avoids inaccurate Profiler durations in the case of a1150 // suspended render.1151 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);1152 }1153 throwException(1154 root,1155 erroredWork.return,1156 erroredWork,1157 thrownValue,1158 workInProgressRootRenderLanes,1159 );1160 completeUnitOfWork(erroredWork);1161 } catch (yetAnotherThrownValue) {1162 // Something in the return path also threw.1163 thrownValue = yetAnotherThrownValue;1164 if (workInProgress === erroredWork && erroredWork !== null) {1165 // If this boundary has already errored, then we had trouble processing1166 // the error. Bubble it to the next boundary.1167 erroredWork = erroredWork.return;1168 workInProgress = erroredWork;1169 } else {1170 erroredWork = workInProgress;1171 }1172 continue;1173 }1174 // Return to the normal work loop.1175 return;1176 } while (true);1177}1178function pushDispatcher() {1179 const prevDispatcher = ReactCurrentDispatcher.current;1180 ReactCurrentDispatcher.current = ContextOnlyDispatcher;1181 if (prevDispatcher === null) {1182 // The React isomorphic package does not include a default dispatcher.1183 // Instead the first renderer will lazily attach one, in order to give1184 // nicer error messages.1185 return ContextOnlyDispatcher;1186 } else {1187 return prevDispatcher;1188 }1189}1190function popDispatcher(prevDispatcher) {1191 ReactCurrentDispatcher.current = prevDispatcher;1192}1193function pushInteractions(root) {1194 if (enableSchedulerTracing) {1195 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1196 __interactionsRef.current = root.memoizedInteractions;1197 return prevInteractions;1198 }1199 return null;1200}1201function popInteractions(prevInteractions) {1202 if (enableSchedulerTracing) {1203 __interactionsRef.current = prevInteractions;1204 }1205}1206export function markCommitTimeOfFallback() {1207 globalMostRecentFallbackTime = now();1208}1209export function markSkippedUpdateLanes(lane: Lane | Lanes): void {1210 workInProgressRootSkippedLanes = mergeLanes(1211 lane,1212 workInProgressRootSkippedLanes,1213 );1214}1215export function renderDidSuspend(): void {1216 if (workInProgressRootExitStatus === RootIncomplete) {1217 workInProgressRootExitStatus = RootSuspended;1218 }1219}1220export function renderDidSuspendDelayIfPossible(): void {1221 if (1222 workInProgressRootExitStatus === RootIncomplete ||1223 workInProgressRootExitStatus === RootSuspended1224 ) {1225 workInProgressRootExitStatus = RootSuspendedWithDelay;1226 }1227 // Check if there are updates that we skipped tree that might have unblocked1228 // this render.1229 if (1230 workInProgressRoot !== null &&1231 (includesNonIdleWork(workInProgressRootSkippedLanes) ||1232 includesNonIdleWork(workInProgressRootUpdatedLanes))1233 ) {1234 // Mark the current render as suspended so that we switch to working on1235 // the updates that were skipped. Usually we only suspend at the end of1236 // the render phase.1237 // TODO: We should probably always mark the root as suspended immediately1238 // (inside this function), since by suspending at the end of the render1239 // phase introduces a potential mistake where we suspend lanes that were1240 // pinged or updated while we were rendering.1241 markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes);1242 }1243}1244export function renderDidError() {1245 if (workInProgressRootExitStatus !== RootCompleted) {1246 workInProgressRootExitStatus = RootErrored;1247 }1248}1249// Called during render to determine if anything has suspended.1250// Returns false if we're not sure.1251export function renderHasNotSuspendedYet(): boolean {1252 // If something errored or completed, we can't really be sure,1253 // so those are false.1254 return workInProgressRootExitStatus === RootIncomplete;1255}1256function renderRootSync(root: FiberRoot, lanes: Lanes) {1257 1258 enableLog && console.log('renderRootSync')1259 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('renderRootSync')) debugger1260 1261 const prevExecutionContext = executionContext;1262 executionContext |= RenderContext;1263 const prevDispatcher = pushDispatcher();1264 // If the root or lanes have changed, throw out the existing stack1265 // and prepare a fresh one. Otherwise we'll continue where we left off.1266 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1267 prepareFreshStack(root, lanes);1268 startWorkOnPendingInteractions(root, lanes);1269 }1270 const prevInteractions = pushInteractions(root);1271 do {1272 try {1273 workLoopSync();1274 break;1275 } catch (thrownValue) {1276 handleError(root, thrownValue);1277 }1278 } while (true);1279 resetContextDependencies();1280 if (enableSchedulerTracing) {1281 popInteractions(((prevInteractions: any): Set<Interaction>));1282 }1283 executionContext = prevExecutionContext;1284 popDispatcher(prevDispatcher);1285 if (workInProgress !== null) {1286 // This is a sync render, so we should have finished the whole tree.1287 invariant(1288 false,1289 'Cannot commit an incomplete root. This error is likely caused by a ' +1290 'bug in React. Please file an issue.',1291 );1292 }1293 // Set this to null to indicate there's no in-progress render.1294 workInProgressRoot = null;1295 workInProgressRootRenderLanes = NoLanes;1296 return workInProgressRootExitStatus;1297}1298// The work loop is an extremely hot path. Tell Closure not to inline it.1299/** @noinline */1300function workLoopSync() {1301 1302 enableLog && console.log('workLoopSync')1303 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('workLoopSync')) debugger1304 // Already timed out, so perform work without checking if we need to yield.1305 while (workInProgress !== null) {1306 enableLog && console.log('workLoopSync in while')1307 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('workLoopSync')) debugger1308 performUnitOfWork(workInProgress);1309 }1310}1311function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {1312 1313 enableLog && console.log('renderRootConcurrent start')1314 if (!__LOG_NAMES__.length || __LOG_NAMES__.includes('renderRootConcurrent')) debugger1315 const prevExecutionContext = executionContext;1316 executionContext |= RenderContext;1317 const prevDispatcher = pushDispatcher();1318 // If the root or lanes have changed, throw out the existing stack1319 // and prepare a fresh one. Otherwise we'll continue where we left off.1320 // root或者lane改变,都会调用prepareFreshStack刷新栈帧, 丢弃上一次渲染进度1321 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1322 resetRenderTimer();1323 // prepareFreshStack里面会通过workInProgress = createWorkInProgress(root.current, null)创建workInProgress1324 prepareFreshStack(root, lanes);1325 startWorkOnPendingInteractions(root, lanes);...

Full Screen

Full Screen

ReactFiberWorkLoop.js

Source:ReactFiberWorkLoop.js Github

copy

Full Screen

...612 (executionContext & (RenderContext | CommitContext)) === NoContext,613 'Should not already be working.',614 );615 flushPassiveEffects();616 let exitStatus = renderRootConcurrent(root, expirationTime);617 if (exitStatus !== RootIncomplete) {618 if (exitStatus === RootErrored) {619 // If something threw an error, try rendering one more time. We'll620 // render synchronously to block concurrent data mutations, and we'll621 // render at Idle (or lower) so that all pending updates are included.622 // If it still fails after the second attempt, we'll give up and commit623 // the resulting tree.624 expirationTime = expirationTime > Idle ? Idle : expirationTime;625 exitStatus = renderRootSync(root, expirationTime);626 }627 if (exitStatus === RootFatalErrored) {628 const fatalError = workInProgressRootFatalError;629 prepareFreshStack(root, expirationTime);630 markRootSuspendedAtTime(root, expirationTime);631 ensureRootIsScheduled(root);632 throw fatalError;633 }634 // We now have a consistent tree. The next step is either to commit it,635 // or, if something suspended, wait to commit it after a timeout.636 const finishedWork: Fiber = ((root.finishedWork =637 root.current.alternate): any);638 root.finishedExpirationTime = expirationTime;639 finishConcurrentRender(root, finishedWork, exitStatus, expirationTime);640 }641 ensureRootIsScheduled(root);642 if (root.callbackNode === originalCallbackNode) {643 // The task node scheduled for this root is the same one that's644 // currently executed. Need to return a continuation.645 return performConcurrentWorkOnRoot.bind(null, root);646 }647 return null;648}649function finishConcurrentRender(650 root,651 finishedWork,652 exitStatus,653 expirationTime,654) {655 switch (exitStatus) {656 case RootIncomplete:657 case RootFatalErrored: {658 invariant(false, 'Root did not complete. This is a bug in React.');659 }660 // Flow knows about invariant, so it complains if I add a break661 // statement, but eslint doesn't know about invariant, so it complains662 // if I do. eslint-disable-next-line no-fallthrough663 case RootErrored: {664 // We should have already attempted to retry this tree. If we reached665 // this point, it errored again. Commit it.666 commitRoot(root);667 break;668 }669 case RootSuspended: {670 markRootSuspendedAtTime(root, expirationTime);671 const lastSuspendedTime = root.lastSuspendedTime;672 if (expirationTime === lastSuspendedTime) {673 root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork);674 }675 // We have an acceptable loading state. We need to figure out if we676 // should immediately commit it or wait a bit.677 // If we have processed new updates during this render, we may now678 // have a new loading state ready. We want to ensure that we commit679 // that as soon as possible.680 const hasNotProcessedNewUpdates =681 workInProgressRootLatestProcessedExpirationTime === Sync;682 if (683 hasNotProcessedNewUpdates &&684 // do not delay if we're inside an act() scope685 !(686 __DEV__ &&687 flushSuspenseFallbacksInTests &&688 IsThisRendererActing.current689 )690 ) {691 // If we have not processed any new updates during this pass, then692 // this is either a retry of an existing fallback state or a693 // hidden tree. Hidden trees shouldn't be batched with other work694 // and after that's fixed it can only be a retry. We're going to695 // throttle committing retries so that we don't show too many696 // loading states too quickly.697 let msUntilTimeout =698 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();699 // Don't bother with a very short suspense time.700 if (msUntilTimeout > 10) {701 if (workInProgressRootHasPendingPing) {702 const lastPingedTime = root.lastPingedTime;703 if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {704 // This render was pinged but we didn't get to restart705 // earlier so try restarting now instead.706 root.lastPingedTime = expirationTime;707 prepareFreshStack(root, expirationTime);708 break;709 }710 }711 const nextTime = getNextRootExpirationTimeToWorkOn(root);712 if (nextTime !== NoWork && nextTime !== expirationTime) {713 // There's additional work on this root.714 break;715 }716 if (717 lastSuspendedTime !== NoWork &&718 lastSuspendedTime !== expirationTime719 ) {720 // We should prefer to render the fallback of at the last721 // suspended level. Ping the last suspended level to try722 // rendering it again.723 root.lastPingedTime = lastSuspendedTime;724 break;725 }726 // The render is suspended, it hasn't timed out, and there's no727 // lower priority work to do. Instead of committing the fallback728 // immediately, wait for more data to arrive.729 root.timeoutHandle = scheduleTimeout(730 commitRoot.bind(null, root),731 msUntilTimeout,732 );733 break;734 }735 }736 // The work expired. Commit immediately.737 commitRoot(root);738 break;739 }740 case RootSuspendedWithDelay: {741 markRootSuspendedAtTime(root, expirationTime);742 const lastSuspendedTime = root.lastSuspendedTime;743 if (expirationTime === lastSuspendedTime) {744 root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork);745 }746 if (747 // do not delay if we're inside an act() scope748 !(749 __DEV__ &&750 flushSuspenseFallbacksInTests &&751 IsThisRendererActing.current752 )753 ) {754 // We're suspended in a state that should be avoided. We'll try to755 // avoid committing it for as long as the timeouts let us.756 if (workInProgressRootHasPendingPing) {757 const lastPingedTime = root.lastPingedTime;758 if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {759 // This render was pinged but we didn't get to restart earlier760 // so try restarting now instead.761 root.lastPingedTime = expirationTime;762 prepareFreshStack(root, expirationTime);763 break;764 }765 }766 const nextTime = getNextRootExpirationTimeToWorkOn(root);767 if (nextTime !== NoWork && nextTime !== expirationTime) {768 // There's additional work on this root.769 break;770 }771 if (772 lastSuspendedTime !== NoWork &&773 lastSuspendedTime !== expirationTime774 ) {775 // We should prefer to render the fallback of at the last776 // suspended level. Ping the last suspended level to try777 // rendering it again.778 root.lastPingedTime = lastSuspendedTime;779 break;780 }781 let msUntilTimeout;782 if (workInProgressRootLatestSuspenseTimeout !== Sync) {783 // We have processed a suspense config whose expiration time we784 // can use as the timeout.785 msUntilTimeout =786 expirationTimeToMs(workInProgressRootLatestSuspenseTimeout) - now();787 } else if (workInProgressRootLatestProcessedExpirationTime === Sync) {788 // This should never normally happen because only new updates789 // cause delayed states, so we should have processed something.790 // However, this could also happen in an offscreen tree.791 msUntilTimeout = 0;792 } else {793 // If we don't have a suspense config, we're going to use a794 // heuristic to determine how long we can suspend.795 const eventTimeMs: number = inferTimeFromExpirationTime(796 workInProgressRootLatestProcessedExpirationTime,797 );798 const currentTimeMs = now();799 const timeUntilExpirationMs =800 expirationTimeToMs(expirationTime) - currentTimeMs;801 let timeElapsed = currentTimeMs - eventTimeMs;802 if (timeElapsed < 0) {803 // We get this wrong some time since we estimate the time.804 timeElapsed = 0;805 }806 msUntilTimeout = jnd(timeElapsed) - timeElapsed;807 // Clamp the timeout to the expiration time. TODO: Once the808 // event time is exact instead of inferred from expiration time809 // we don't need this.810 if (timeUntilExpirationMs < msUntilTimeout) {811 msUntilTimeout = timeUntilExpirationMs;812 }813 }814 // Don't bother with a very short suspense time.815 if (msUntilTimeout > 10) {816 // The render is suspended, it hasn't timed out, and there's no817 // lower priority work to do. Instead of committing the fallback818 // immediately, wait for more data to arrive.819 root.timeoutHandle = scheduleTimeout(820 commitRoot.bind(null, root),821 msUntilTimeout,822 );823 break;824 }825 }826 // The work expired. Commit immediately.827 commitRoot(root);828 break;829 }830 case RootCompleted: {831 // The work completed. Ready to commit.832 if (833 // do not delay if we're inside an act() scope834 !(835 __DEV__ &&836 flushSuspenseFallbacksInTests &&837 IsThisRendererActing.current838 ) &&839 workInProgressRootLatestProcessedExpirationTime !== Sync &&840 workInProgressRootCanSuspendUsingConfig !== null841 ) {842 // If we have exceeded the minimum loading delay, which probably843 // means we have shown a spinner already, we might have to suspend844 // a bit longer to ensure that the spinner is shown for845 // enough time.846 const msUntilTimeout = computeMsUntilSuspenseLoadingDelay(847 workInProgressRootLatestProcessedExpirationTime,848 expirationTime,849 workInProgressRootCanSuspendUsingConfig,850 );851 if (msUntilTimeout > 10) {852 markRootSuspendedAtTime(root, expirationTime);853 root.timeoutHandle = scheduleTimeout(854 commitRoot.bind(null, root),855 msUntilTimeout,856 );857 break;858 }859 }860 commitRoot(root);861 break;862 }863 default: {864 invariant(false, 'Unknown root exit status.');865 }866 }867}868// This is the entry point for synchronous tasks that don't go869// through Scheduler870function performSyncWorkOnRoot(root) {871 invariant(872 (executionContext & (RenderContext | CommitContext)) === NoContext,873 'Should not already be working.',874 );875 flushPassiveEffects();876 const lastExpiredTime = root.lastExpiredTime;877 let expirationTime;878 if (lastExpiredTime !== NoWork) {879 // There's expired work on this root. Check if we have a partial tree880 // that we can reuse.881 if (882 root === workInProgressRoot &&883 renderExpirationTime >= lastExpiredTime884 ) {885 // There's a partial tree with equal or greater than priority than the886 // expired level. Finish rendering it before rendering the rest of the887 // expired work.888 expirationTime = renderExpirationTime;889 } else {890 // Start a fresh tree.891 expirationTime = lastExpiredTime;892 }893 } else {894 // There's no expired work. This must be a new, synchronous render.895 expirationTime = Sync;896 }897 let exitStatus = renderRootSync(root, expirationTime);898 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {899 // If something threw an error, try rendering one more time. We'll900 // render synchronously to block concurrent data mutations, and we'll901 // render at Idle (or lower) so that all pending updates are included.902 // If it still fails after the second attempt, we'll give up and commit903 // the resulting tree.904 expirationTime = expirationTime > Idle ? Idle : expirationTime;905 exitStatus = renderRootSync(root, expirationTime);906 }907 if (exitStatus === RootFatalErrored) {908 const fatalError = workInProgressRootFatalError;909 prepareFreshStack(root, expirationTime);910 markRootSuspendedAtTime(root, expirationTime);911 ensureRootIsScheduled(root);912 throw fatalError;913 }914 // We now have a consistent tree. Because this is a sync render, we915 // will commit it even if something suspended.916 root.finishedWork = (root.current.alternate: any);917 root.finishedExpirationTime = expirationTime;918 commitRoot(root);919 // Before exiting, make sure there's a callback scheduled for the next920 // pending level.921 ensureRootIsScheduled(root);922 return null;923}924export function flushRoot(root: FiberRoot, expirationTime: ExpirationTime) {925 markRootExpiredAtTime(root, expirationTime);926 ensureRootIsScheduled(root);927 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {928 flushSyncCallbackQueue();929 }930}931export function flushDiscreteUpdates() {932 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.933 // However, `act` uses `batchedUpdates`, so there's no way to distinguish934 // those two cases. Need to fix this before exposing flushDiscreteUpdates935 // as a public API.936 if (937 (executionContext & (BatchedContext | RenderContext | CommitContext)) !==938 NoContext939 ) {940 if (__DEV__) {941 if ((executionContext & RenderContext) !== NoContext) {942 console.error(943 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +944 'already rendering.',945 );946 }947 }948 // We're already rendering, so we can't synchronously flush pending work.949 // This is probably a nested event dispatch triggered by a lifecycle/effect,950 // like `el.focus()`. Exit.951 return;952 }953 flushPendingDiscreteUpdates();954 // If the discrete updates scheduled passive effects, flush them now so that955 // they fire before the next serial event.956 flushPassiveEffects();957}958export function deferredUpdates<A>(fn: () => A): A {959 // TODO: Remove in favor of Scheduler.next960 return runWithPriority(NormalPriority, fn);961}962export function syncUpdates<A, B, C, R>(963 fn: (A, B, C) => R,964 a: A,965 b: B,966 c: C,967): R {968 return runWithPriority(ImmediatePriority, fn.bind(null, a, b, c));969}970function flushPendingDiscreteUpdates() {971 if (rootsWithPendingDiscreteUpdates !== null) {972 // For each root with pending discrete updates, schedule a callback to973 // immediately flush them.974 const roots = rootsWithPendingDiscreteUpdates;975 rootsWithPendingDiscreteUpdates = null;976 roots.forEach((expirationTime, root) => {977 markRootExpiredAtTime(root, expirationTime);978 ensureRootIsScheduled(root);979 });980 // Now flush the immediate queue.981 flushSyncCallbackQueue();982 }983}984export function batchedUpdates<A, R>(fn: A => R, a: A): R {985 const prevExecutionContext = executionContext;986 executionContext |= BatchedContext;987 try {988 return fn(a);989 } finally {990 executionContext = prevExecutionContext;991 if (executionContext === NoContext) {992 // Flush the immediate callbacks that were scheduled during this batch993 flushSyncCallbackQueue();994 }995 }996}997export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {998 const prevExecutionContext = executionContext;999 executionContext |= EventContext;1000 try {1001 return fn(a);1002 } finally {1003 executionContext = prevExecutionContext;1004 if (executionContext === NoContext) {1005 // Flush the immediate callbacks that were scheduled during this batch1006 flushSyncCallbackQueue();1007 }1008 }1009}1010export function discreteUpdates<A, B, C, D, R>(1011 fn: (A, B, C) => R,1012 a: A,1013 b: B,1014 c: C,1015 d: D,1016): R {1017 const prevExecutionContext = executionContext;1018 executionContext |= DiscreteEventContext;1019 try {1020 // Should this1021 return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c, d));1022 } finally {1023 executionContext = prevExecutionContext;1024 if (executionContext === NoContext) {1025 // Flush the immediate callbacks that were scheduled during this batch1026 flushSyncCallbackQueue();1027 }1028 }1029}1030export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1031 const prevExecutionContext = executionContext;1032 executionContext &= ~BatchedContext;1033 executionContext |= LegacyUnbatchedContext;1034 try {1035 return fn(a);1036 } finally {1037 executionContext = prevExecutionContext;1038 if (executionContext === NoContext) {1039 // Flush the immediate callbacks that were scheduled during this batch1040 flushSyncCallbackQueue();1041 }1042 }1043}1044export function flushSync<A, R>(fn: A => R, a: A): R {1045 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {1046 invariant(1047 false,1048 'flushSync was called from inside a lifecycle method. It cannot be ' +1049 'called when React is already rendering.',1050 );1051 }1052 const prevExecutionContext = executionContext;1053 executionContext |= BatchedContext;1054 try {1055 return runWithPriority(ImmediatePriority, fn.bind(null, a));1056 } finally {1057 executionContext = prevExecutionContext;1058 // Flush the immediate callbacks that were scheduled during this batch.1059 // Note that this will happen even if batchedUpdates is higher up1060 // the stack.1061 flushSyncCallbackQueue();1062 }1063}1064export function flushControlled(fn: () => mixed): void {1065 const prevExecutionContext = executionContext;1066 executionContext |= BatchedContext;1067 try {1068 runWithPriority(ImmediatePriority, fn);1069 } finally {1070 executionContext = prevExecutionContext;1071 if (executionContext === NoContext) {1072 // Flush the immediate callbacks that were scheduled during this batch1073 flushSyncCallbackQueue();1074 }1075 }1076}1077function prepareFreshStack(root, expirationTime) {1078 root.finishedWork = null;1079 root.finishedExpirationTime = NoWork;1080 const timeoutHandle = root.timeoutHandle;1081 if (timeoutHandle !== noTimeout) {1082 // The root previous suspended and scheduled a timeout to commit a fallback1083 // state. Now that we have additional work, cancel the timeout.1084 root.timeoutHandle = noTimeout;1085 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1086 cancelTimeout(timeoutHandle);1087 }1088 if (workInProgress !== null) {1089 let interruptedWork = workInProgress.return;1090 while (interruptedWork !== null) {1091 unwindInterruptedWork(interruptedWork);1092 interruptedWork = interruptedWork.return;1093 }1094 }1095 workInProgressRoot = root;1096 workInProgress = createWorkInProgress(root.current, null);1097 renderExpirationTime = expirationTime;1098 workInProgressRootExitStatus = RootIncomplete;1099 workInProgressRootFatalError = null;1100 workInProgressRootLatestProcessedExpirationTime = Sync;1101 workInProgressRootLatestSuspenseTimeout = Sync;1102 workInProgressRootCanSuspendUsingConfig = null;1103 workInProgressRootNextUnprocessedUpdateTime = NoWork;1104 workInProgressRootHasPendingPing = false;1105 if (enableSchedulerTracing) {1106 spawnedWorkDuringRender = null;1107 }1108 if (__DEV__) {1109 ReactStrictModeWarnings.discardPendingWarnings();1110 }1111}1112function handleError(root, thrownValue) {1113 do {1114 try {1115 // Reset module-level state that was set during the render phase.1116 resetContextDependencies();1117 resetHooksAfterThrow();1118 resetCurrentDebugFiberInDEV();1119 if (workInProgress === null || workInProgress.return === null) {1120 // Expected to be working on a non-root fiber. This is a fatal error1121 // because there's no ancestor that can handle it; the root is1122 // supposed to capture all errors that weren't caught by an error1123 // boundary.1124 workInProgressRootExitStatus = RootFatalErrored;1125 workInProgressRootFatalError = thrownValue;1126 // Set `workInProgress` to null. This represents advancing to the next1127 // sibling, or the parent if there are no siblings. But since the root1128 // has no siblings nor a parent, we set it to null. Usually this is1129 // handled by `completeUnitOfWork` or `unwindWork`, but since we're1130 // interntionally not calling those, we need set it here.1131 // TODO: Consider calling `unwindWork` to pop the contexts.1132 workInProgress = null;1133 return null;1134 }1135 if (enableProfilerTimer && workInProgress.mode & ProfileMode) {1136 // Record the time spent rendering before an error was thrown. This1137 // avoids inaccurate Profiler durations in the case of a1138 // suspended render.1139 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);1140 }1141 throwException(1142 root,1143 workInProgress.return,1144 workInProgress,1145 thrownValue,1146 renderExpirationTime,1147 );1148 workInProgress = completeUnitOfWork(workInProgress);1149 } catch (yetAnotherThrownValue) {1150 // Something in the return path also threw.1151 thrownValue = yetAnotherThrownValue;1152 continue;1153 }1154 // Return to the normal work loop.1155 return;1156 } while (true);1157}1158function pushDispatcher(root) {1159 const prevDispatcher = ReactCurrentDispatcher.current;1160 ReactCurrentDispatcher.current = ContextOnlyDispatcher;1161 if (prevDispatcher === null) {1162 // The React isomorphic package does not include a default dispatcher.1163 // Instead the first renderer will lazily attach one, in order to give1164 // nicer error messages.1165 return ContextOnlyDispatcher;1166 } else {1167 return prevDispatcher;1168 }1169}1170function popDispatcher(prevDispatcher) {1171 ReactCurrentDispatcher.current = prevDispatcher;1172}1173function pushInteractions(root) {1174 if (enableSchedulerTracing) {1175 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1176 __interactionsRef.current = root.memoizedInteractions;1177 return prevInteractions;1178 }1179 return null;1180}1181function popInteractions(prevInteractions) {1182 if (enableSchedulerTracing) {1183 __interactionsRef.current = prevInteractions;1184 }1185}1186export function markCommitTimeOfFallback() {1187 globalMostRecentFallbackTime = now();1188}1189export function markRenderEventTimeAndConfig(1190 expirationTime: ExpirationTime,1191 suspenseConfig: null | SuspenseConfig,1192): void {1193 if (1194 expirationTime < workInProgressRootLatestProcessedExpirationTime &&1195 expirationTime > Idle1196 ) {1197 workInProgressRootLatestProcessedExpirationTime = expirationTime;1198 }1199 if (suspenseConfig !== null) {1200 if (1201 expirationTime < workInProgressRootLatestSuspenseTimeout &&1202 expirationTime > Idle1203 ) {1204 workInProgressRootLatestSuspenseTimeout = expirationTime;1205 // Most of the time we only have one config and getting wrong is not bad.1206 workInProgressRootCanSuspendUsingConfig = suspenseConfig;1207 }1208 }1209}1210export function markUnprocessedUpdateTime(1211 expirationTime: ExpirationTime,1212): void {1213 if (expirationTime > workInProgressRootNextUnprocessedUpdateTime) {1214 workInProgressRootNextUnprocessedUpdateTime = expirationTime;1215 }1216}1217export function renderDidSuspend(): void {1218 if (workInProgressRootExitStatus === RootIncomplete) {1219 workInProgressRootExitStatus = RootSuspended;1220 }1221}1222export function renderDidSuspendDelayIfPossible(): void {1223 if (1224 workInProgressRootExitStatus === RootIncomplete ||1225 workInProgressRootExitStatus === RootSuspended1226 ) {1227 workInProgressRootExitStatus = RootSuspendedWithDelay;1228 }1229 // Check if there's a lower priority update somewhere else in the tree.1230 if (1231 workInProgressRootNextUnprocessedUpdateTime !== NoWork &&1232 workInProgressRoot !== null1233 ) {1234 // Mark the current render as suspended, and then mark that there's a1235 // pending update.1236 // TODO: This should immediately interrupt the current render, instead1237 // of waiting until the next time we yield.1238 markRootSuspendedAtTime(workInProgressRoot, renderExpirationTime);1239 markRootUpdatedAtTime(1240 workInProgressRoot,1241 workInProgressRootNextUnprocessedUpdateTime,1242 );1243 }1244}1245export function renderDidError() {1246 if (workInProgressRootExitStatus !== RootCompleted) {1247 workInProgressRootExitStatus = RootErrored;1248 }1249}1250// Called during render to determine if anything has suspended.1251// Returns false if we're not sure.1252export function renderHasNotSuspendedYet(): boolean {1253 // If something errored or completed, we can't really be sure,1254 // so those are false.1255 return workInProgressRootExitStatus === RootIncomplete;1256}1257function inferTimeFromExpirationTime(expirationTime: ExpirationTime): number {1258 // We don't know exactly when the update was scheduled, but we can infer an1259 // approximate start time from the expiration time.1260 const earliestExpirationTimeMs = expirationTimeToMs(expirationTime);1261 return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;1262}1263function inferTimeFromExpirationTimeWithSuspenseConfig(1264 expirationTime: ExpirationTime,1265 suspenseConfig: SuspenseConfig,1266): number {1267 // We don't know exactly when the update was scheduled, but we can infer an1268 // approximate start time from the expiration time by subtracting the timeout1269 // that was added to the event time.1270 const earliestExpirationTimeMs = expirationTimeToMs(expirationTime);1271 return (1272 earliestExpirationTimeMs -1273 (suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION)1274 );1275}1276function renderRootSync(root, expirationTime) {1277 const prevExecutionContext = executionContext;1278 executionContext |= RenderContext;1279 const prevDispatcher = pushDispatcher(root);1280 // If the root or expiration time have changed, throw out the existing stack1281 // and prepare a fresh one. Otherwise we'll continue where we left off.1282 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {1283 prepareFreshStack(root, expirationTime);1284 startWorkOnPendingInteractions(root, expirationTime);1285 }1286 const prevInteractions = pushInteractions(root);1287 startWorkLoopTimer(workInProgress);1288 do {1289 try {1290 workLoopSync();1291 break;1292 } catch (thrownValue) {1293 handleError(root, thrownValue);1294 }1295 } while (true);1296 resetContextDependencies();1297 if (enableSchedulerTracing) {1298 popInteractions(((prevInteractions: any): Set<Interaction>));1299 }1300 executionContext = prevExecutionContext;1301 popDispatcher(prevDispatcher);1302 if (workInProgress !== null) {1303 // This is a sync render, so we should have finished the whole tree.1304 invariant(1305 false,1306 'Cannot commit an incomplete root. This error is likely caused by a ' +1307 'bug in React. Please file an issue.',1308 );1309 }1310 stopFinishedWorkLoopTimer();1311 // Set this to null to indicate there's no in-progress render.1312 workInProgressRoot = null;1313 return workInProgressRootExitStatus;1314}1315// The work loop is an extremely hot path. Tell Closure not to inline it.1316/** @noinline */1317function workLoopSync() {1318 // Already timed out, so perform work without checking if we need to yield.1319 while (workInProgress !== null) {1320 workInProgress = performUnitOfWork(workInProgress);1321 }1322}1323function renderRootConcurrent(root, expirationTime) {1324 const prevExecutionContext = executionContext;1325 executionContext |= RenderContext;1326 const prevDispatcher = pushDispatcher(root);1327 // If the root or expiration time have changed, throw out the existing stack1328 // and prepare a fresh one. Otherwise we'll continue where we left off.1329 if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {1330 prepareFreshStack(root, expirationTime);1331 startWorkOnPendingInteractions(root, expirationTime);1332 }1333 const prevInteractions = pushInteractions(root);1334 startWorkLoopTimer(workInProgress);1335 do {1336 try {1337 workLoopConcurrent();...

Full Screen

Full Screen

ReactFiberWorkLoop.old.js

Source:ReactFiberWorkLoop.old.js Github

copy

Full Screen

...363 if (lanes === NoLanes) {364 // Defensive coding. This is never expected to happen.365 return null;366 }367 var exitStatus = renderRootConcurrent(root, lanes);368 if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {369 // The render included lanes that were updated during the render phase.370 // For example, when unhiding a hidden tree, we include all the lanes371 // that were previously skipped when the tree was hidden. That set of372 // lanes is a superset of the lanes we started rendering with.373 //374 // So we'll throw out the current work and restart.375 prepareFreshStack(root, NoLanes);376 } else if (exitStatus !== RootIncomplete) {377 if (exitStatus === RootErrored) {378 executionContext |= RetryAfterError; // If an error occurred during hydration,379 // discard server response and fall back to client side render.380 if (root.hydrate) {381 root.hydrate = false;382 clearContainer(root.containerInfo);383 } // If something threw an error, try rendering one more time. We'll render384 // synchronously to block concurrent data mutations, and we'll includes385 // all pending updates are included. If it still fails after the second386 // attempt, we'll give up and commit the resulting tree.387 lanes = getLanesToRetrySynchronouslyOnError(root);388 if (lanes !== NoLanes) {389 exitStatus = renderRootSync(root, lanes);390 }391 }392 if (exitStatus === RootFatalErrored) {393 var fatalError = workInProgressRootFatalError;394 prepareFreshStack(root, NoLanes);395 markRootSuspended$1(root, lanes);396 ensureRootIsScheduled(root, now());397 throw fatalError;398 } // We now have a consistent tree. The next step is either to commit it,399 // or, if something suspended, wait to commit it after a timeout.400 var finishedWork = root.current.alternate;401 root.finishedWork = finishedWork;402 root.finishedLanes = lanes;403 finishConcurrentRender(root, exitStatus, lanes);404 }405 ensureRootIsScheduled(root, now());406 if (root.callbackNode === originalCallbackNode) {407 // The task node scheduled for this root is the same one that's408 // currently executed. Need to return a continuation.409 return performConcurrentWorkOnRoot.bind(null, root);410 }411 return null;412 }413 function finishConcurrentRender(root, exitStatus, lanes) {414 switch (exitStatus) {415 case RootIncomplete:416 case RootFatalErrored:417 {418 {419 {420 throw Error( "Root did not complete. This is a bug in React." );421 }422 }423 }424 // Flow knows about invariant, so it complains if I add a break425 // statement, but eslint doesn't know about invariant, so it complains426 // if I do. eslint-disable-next-line no-fallthrough427 case RootErrored:428 {429 // We should have already attempted to retry this tree. If we reached430 // this point, it errored again. Commit it.431 commitRoot(root);432 break;433 }434 case RootSuspended:435 {436 markRootSuspended$1(root, lanes); // We have an acceptable loading state. We need to figure out if we437 // should immediately commit it or wait a bit.438 if (includesOnlyRetries(lanes) && // do not delay if we're inside an act() scope439 !shouldForceFlushFallbacksInDEV()) {440 // This render only included retries, no updates. Throttle committing441 // retries so that we don't show too many loading states too quickly.442 var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now(); // Don't bother with a very short suspense time.443 if (msUntilTimeout > 10) {444 var nextLanes = getNextLanes(root, NoLanes);445 if (nextLanes !== NoLanes) {446 // There's additional work on this root.447 break;448 }449 var suspendedLanes = root.suspendedLanes;450 if (!isSubsetOfLanes(suspendedLanes, lanes)) {451 // We should prefer to render the fallback of at the last452 // suspended level. Ping the last suspended level to try453 // rendering it again.454 // FIXME: What if the suspended lanes are Idle? Should not restart.455 var eventTime = requestEventTime();456 markRootPinged(root, suspendedLanes);457 break;458 } // The render is suspended, it hasn't timed out, and there's no459 // lower priority work to do. Instead of committing the fallback460 // immediately, wait for more data to arrive.461 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), msUntilTimeout);462 break;463 }464 } // The work expired. Commit immediately.465 commitRoot(root);466 break;467 }468 case RootSuspendedWithDelay:469 {470 markRootSuspended$1(root, lanes);471 if (includesOnlyTransitions(lanes)) {472 // This is a transition, so we should exit without committing a473 // placeholder and without scheduling a timeout. Delay indefinitely474 // until we receive more data.475 break;476 }477 if (!shouldForceFlushFallbacksInDEV()) {478 // This is not a transition, but we did trigger an avoided state.479 // Schedule a placeholder to display after a short delay, using the Just480 // Noticeable Difference.481 // TODO: Is the JND optimization worth the added complexity? If this is482 // the only reason we track the event time, then probably not.483 // Consider removing.484 var mostRecentEventTime = getMostRecentEventTime(root, lanes);485 var eventTimeMs = mostRecentEventTime;486 var timeElapsedMs = now() - eventTimeMs;487 var _msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs; // Don't bother with a very short suspense time.488 if (_msUntilTimeout > 10) {489 // Instead of committing the fallback immediately, wait for more data490 // to arrive.491 root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout);492 break;493 }494 } // Commit the placeholder.495 commitRoot(root);496 break;497 }498 case RootCompleted:499 {500 // The work completed. Ready to commit.501 commitRoot(root);502 break;503 }504 default:505 {506 {507 {508 throw Error( "Unknown root exit status." );509 }510 }511 }512 }513 }514 function markRootSuspended$1(root, suspendedLanes) {515 // When suspending, we should always exclude lanes that were pinged or (more516 // rarely, since we try to avoid it) updated during the render phase.517 // TODO: Lol maybe there's a better way to factor this besides this518 // obnoxiously named function :)519 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);520 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);521 markRootSuspended(root, suspendedLanes);522 } // This is the entry point for synchronous tasks that don't go523 // through Scheduler524 function performSyncWorkOnRoot(root) {525 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {526 {527 throw Error( "Should not already be working." );528 }529 }530 flushPassiveEffects();531 var lanes;532 var exitStatus;533 if (root === workInProgressRoot && includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)) {534 // There's a partial tree, and at least one of its lanes has expired. Finish535 // rendering it before rendering the rest of the expired work.536 lanes = workInProgressRootRenderLanes;537 exitStatus = renderRootSync(root, lanes);538 if (includesSomeLane(workInProgressRootIncludedLanes, workInProgressRootUpdatedLanes)) {539 // The render included lanes that were updated during the render phase.540 // For example, when unhiding a hidden tree, we include all the lanes541 // that were previously skipped when the tree was hidden. That set of542 // lanes is a superset of the lanes we started rendering with.543 //544 // Note that this only happens when part of the tree is rendered545 // concurrently. If the whole tree is rendered synchronously, then there546 // are no interleaved events.547 lanes = getNextLanes(root, lanes);548 exitStatus = renderRootSync(root, lanes);549 }550 } else {551 lanes = getNextLanes(root, NoLanes);552 exitStatus = renderRootSync(root, lanes);553 }554 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {555 executionContext |= RetryAfterError; // If an error occurred during hydration,556 // discard server response and fall back to client side render.557 if (root.hydrate) {558 root.hydrate = false;559 clearContainer(root.containerInfo);560 } // If something threw an error, try rendering one more time. We'll render561 // synchronously to block concurrent data mutations, and we'll includes562 // all pending updates are included. If it still fails after the second563 // attempt, we'll give up and commit the resulting tree.564 lanes = getLanesToRetrySynchronouslyOnError(root);565 if (lanes !== NoLanes) {566 exitStatus = renderRootSync(root, lanes);567 }568 }569 if (exitStatus === RootFatalErrored) {570 var fatalError = workInProgressRootFatalError;571 prepareFreshStack(root, NoLanes);572 markRootSuspended$1(root, lanes);573 ensureRootIsScheduled(root, now());574 throw fatalError;575 } // We now have a consistent tree. Because this is a sync render, we576 // will commit it even if something suspended.577 var finishedWork = root.current.alternate;578 root.finishedWork = finishedWork;579 root.finishedLanes = lanes;580 commitRoot(root); // Before exiting, make sure there's a callback scheduled for the next581 // pending level.582 ensureRootIsScheduled(root, now());583 return null;584 }585 function flushRoot(root, lanes) {586 markRootExpired(root, lanes);587 ensureRootIsScheduled(root, now());588 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {589 resetRenderTimer();590 flushSyncCallbackQueue();591 }592 }593 function getExecutionContext() {594 return executionContext;595 }596 // flush react事件597 function flushDiscreteUpdates() {598 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.599 // However, `act` uses `batchedUpdates`, so there's no way to distinguish600 // those two cases. Need to fix this before exposing flushDiscreteUpdates601 // as a public API.602 if ((executionContext & (BatchedContext | RenderContext | CommitContext)) !== NoContext) {603 {604 if ((executionContext & RenderContext) !== NoContext) {605 error('unstable_flushDiscreteUpdates: Cannot flush updates when React is ' + 'already rendering.');606 }607 } // We're already rendering, so we can't synchronously flush pending work.608 // This is probably a nested event dispatch triggered by a lifecycle/effect,609 // like `el.focus()`. Exit.610 return;611 }612 flushPendingDiscreteUpdates(); // If the discrete updates scheduled passive effects, flush them now so that613 // they fire before the next serial event.614 flushPassiveEffects();615 }616 function flushPendingDiscreteUpdates() {617 if (rootsWithPendingDiscreteUpdates !== null) {618 // For each root with pending discrete updates, schedule a callback to619 // immediately flush them.620 var roots = rootsWithPendingDiscreteUpdates;621 rootsWithPendingDiscreteUpdates = null;622 roots.forEach(function (root) {623 markDiscreteUpdatesExpired(root);624 ensureRootIsScheduled(root, now());625 });626 } // Now flush the immediate queue.627 flushSyncCallbackQueue();628 }629 function batchedUpdates$1(fn, a) {630 var prevExecutionContext = executionContext;631 executionContext |= BatchedContext;632 try {633 return fn(a);634 } finally {635 executionContext = prevExecutionContext;636 if (executionContext === NoContext) {637 // Flush the immediate callbacks that were scheduled during this batch638 resetRenderTimer();639 flushSyncCallbackQueue();640 }641 }642 }643 function batchedEventUpdates$1(fn, a) {644 var prevExecutionContext = executionContext;645 executionContext |= EventContext;646 try {647 return fn(a);648 } finally {649 executionContext = prevExecutionContext;650 if (executionContext === NoContext) {651 // Flush the immediate callbacks that were scheduled during this batch652 resetRenderTimer();653 flushSyncCallbackQueue();654 }655 }656 }657 function discreteUpdates$1(fn, a, b, c, d) {658 var prevExecutionContext = executionContext;659 executionContext |= DiscreteEventContext;660 {661 try {662 return runWithPriority$1(UserBlockingPriority$2, fn.bind(null, a, b, c, d));663 } finally {664 executionContext = prevExecutionContext;665 if (executionContext === NoContext) {666 // Flush the immediate callbacks that were scheduled during this batch667 resetRenderTimer();668 flushSyncCallbackQueue();669 }670 }671 }672 }673 // 非批量更新674 function unbatchedUpdates(fn, a) {675 var prevExecutionContext = executionContext;676 executionContext &= ~BatchedContext;677 executionContext |= LegacyUnbatchedContext;678 try {679 return fn(a);680 } finally {681 executionContext = prevExecutionContext;682 if (executionContext === NoContext) {683 // Flush the immediate callbacks that were scheduled during this batch684 resetRenderTimer();685 flushSyncCallbackQueue();686 }687 }688 }689 function flushSync(fn, a) {690 var prevExecutionContext = executionContext;691 if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {692 {693 error('flushSync was called from inside a lifecycle method. React cannot ' + 'flush when React is already rendering. Consider moving this call to ' + 'a scheduler task or micro task.');694 }695 return fn(a);696 }697 executionContext |= BatchedContext;698 {699 try {700 if (fn) {701 return runWithPriority$1(ImmediatePriority$1, fn.bind(null, a));702 } else {703 return undefined;704 }705 } finally {706 executionContext = prevExecutionContext; // Flush the immediate callbacks that were scheduled during this batch.707 // Note that this will happen even if batchedUpdates is higher up708 // the stack.709 flushSyncCallbackQueue();710 }711 }712 }713 function flushControlled(fn) {714 var prevExecutionContext = executionContext;715 executionContext |= BatchedContext;716 {717 try {718 runWithPriority$1(ImmediatePriority$1, fn);719 } finally {720 executionContext = prevExecutionContext;721 if (executionContext === NoContext) {722 // Flush the immediate callbacks that were scheduled during this batch723 resetRenderTimer();724 flushSyncCallbackQueue();725 }726 }727 }728 }729 function pushRenderLanes(fiber, lanes) {730 push(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);731 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);732 workInProgressRootIncludedLanes = mergeLanes(workInProgressRootIncludedLanes, lanes);733 }734 function popRenderLanes(fiber) {735 subtreeRenderLanes = subtreeRenderLanesCursor.current;736 pop(subtreeRenderLanesCursor, fiber);737 }738 function prepareFreshStack(root, lanes) {739 root.finishedWork = null;740 root.finishedLanes = NoLanes;741 var timeoutHandle = root.timeoutHandle;742 if (timeoutHandle !== noTimeout) {743 // The root previous suspended and scheduled a timeout to commit a fallback744 // state. Now that we have additional work, cancel the timeout.745 root.timeoutHandle = noTimeout; // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above746 cancelTimeout(timeoutHandle);747 }748 if (workInProgress !== null) {749 var interruptedWork = workInProgress.return;750 while (interruptedWork !== null) {751 unwindInterruptedWork(interruptedWork);752 interruptedWork = interruptedWork.return;753 }754 }755 workInProgressRoot = root;756 workInProgress = createWorkInProgress(root.current, null);757 workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;758 workInProgressRootExitStatus = RootIncomplete;759 workInProgressRootFatalError = null;760 workInProgressRootSkippedLanes = NoLanes;761 workInProgressRootUpdatedLanes = NoLanes;762 workInProgressRootPingedLanes = NoLanes;763 {764 spawnedWorkDuringRender = null;765 }766 {767 ReactStrictModeWarnings.discardPendingWarnings();768 }769 }770 function handleError(root, thrownValue) {771 do {772 var erroredWork = workInProgress;773 try {774 // Reset module-level state that was set during the render phase.775 resetContextDependencies();776 resetHooksAfterThrow();777 resetCurrentFiber(); // TODO: I found and added this missing line while investigating a778 // separate issue. Write a regression test using string refs.779 ReactCurrentOwner$2.current = null;780 if (erroredWork === null || erroredWork.return === null) {781 // Expected to be working on a non-root fiber. This is a fatal error782 // because there's no ancestor that can handle it; the root is783 // supposed to capture all errors that weren't caught by an error784 // boundary.785 workInProgressRootExitStatus = RootFatalErrored;786 workInProgressRootFatalError = thrownValue; // Set `workInProgress` to null. This represents advancing to the next787 // sibling, or the parent if there are no siblings. But since the root788 // has no siblings nor a parent, we set it to null. Usually this is789 // handled by `completeUnitOfWork` or `unwindWork`, but since we're790 // intentionally not calling those, we need set it here.791 // TODO: Consider calling `unwindWork` to pop the contexts.792 workInProgress = null;793 return;794 }795 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {796 // Record the time spent rendering before an error was thrown. This797 // avoids inaccurate Profiler durations in the case of a798 // suspended render.799 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);800 }801 throwException(root, erroredWork.return, erroredWork, thrownValue, workInProgressRootRenderLanes);802 completeUnitOfWork(erroredWork);803 } catch (yetAnotherThrownValue) {804 // Something in the return path also threw.805 thrownValue = yetAnotherThrownValue;806 if (workInProgress === erroredWork && erroredWork !== null) {807 // If this boundary has already errored, then we had trouble processing808 // the error. Bubble it to the next boundary.809 erroredWork = erroredWork.return;810 workInProgress = erroredWork;811 } else {812 erroredWork = workInProgress;813 }814 continue;815 } // Return to the normal work loop.816 return;817 } while (true);818 }819 function pushDispatcher() {820 var prevDispatcher = ReactCurrentDispatcher$2.current;821 ReactCurrentDispatcher$2.current = ContextOnlyDispatcher;822 if (prevDispatcher === null) {823 // The React isomorphic package does not include a default dispatcher.824 // Instead the first renderer will lazily attach one, in order to give825 // nicer error messages.826 return ContextOnlyDispatcher;827 } else {828 return prevDispatcher;829 }830 }831 function popDispatcher(prevDispatcher) {832 ReactCurrentDispatcher$2.current = prevDispatcher;833 }834 function pushInteractions(root) {835 {836 var prevInteractions = __interactionsRef.current;837 __interactionsRef.current = root.memoizedInteractions;838 return prevInteractions;839 }840 }841 function popInteractions(prevInteractions) {842 {843 __interactionsRef.current = prevInteractions;844 }845 }846 function markCommitTimeOfFallback() {847 globalMostRecentFallbackTime = now();848 }849 function markSkippedUpdateLanes(lane) {850 workInProgressRootSkippedLanes = mergeLanes(lane, workInProgressRootSkippedLanes);851 }852 function renderDidSuspend() {853 if (workInProgressRootExitStatus === RootIncomplete) {854 workInProgressRootExitStatus = RootSuspended;855 }856 }857 function renderDidSuspendDelayIfPossible() {858 if (workInProgressRootExitStatus === RootIncomplete || workInProgressRootExitStatus === RootSuspended) {859 workInProgressRootExitStatus = RootSuspendedWithDelay;860 } // Check if there are updates that we skipped tree that might have unblocked861 // this render.862 if (workInProgressRoot !== null && (includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootUpdatedLanes))) {863 // Mark the current render as suspended so that we switch to working on864 // the updates that were skipped. Usually we only suspend at the end of865 // the render phase.866 // TODO: We should probably always mark the root as suspended immediately867 // (inside this function), since by suspending at the end of the render868 // phase introduces a potential mistake where we suspend lanes that were869 // pinged or updated while we were rendering.870 markRootSuspended$1(workInProgressRoot, workInProgressRootRenderLanes);871 }872 }873 function renderDidError() {874 if (workInProgressRootExitStatus !== RootCompleted) {875 workInProgressRootExitStatus = RootErrored;876 }877 } // Called during render to determine if anything has suspended.878 // Returns false if we're not sure.879 function renderHasNotSuspendedYet() {880 // If something errored or completed, we can't really be sure,881 // so those are false.882 return workInProgressRootExitStatus === RootIncomplete;883 }884 function renderRootSync(root, lanes) {885 var prevExecutionContext = executionContext;886 executionContext |= RenderContext;887 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack888 // and prepare a fresh one. Otherwise we'll continue where we left off.889 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {890 prepareFreshStack(root, lanes);891 startWorkOnPendingInteractions(root, lanes);892 }893 var prevInteractions = pushInteractions(root);894 {895 markRenderStarted(lanes);896 }897 do {898 try {899 workLoopSync();900 break;901 } catch (thrownValue) {902 handleError(root, thrownValue);903 }904 } while (true);905 resetContextDependencies();906 {907 popInteractions(prevInteractions);908 }909 executionContext = prevExecutionContext;910 popDispatcher(prevDispatcher);911 if (workInProgress !== null) {912 // This is a sync render, so we should have finished the whole tree.913 {914 {915 throw Error( "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." );916 }917 }918 }919 {920 markRenderStopped();921 } // Set this to null to indicate there's no in-progress render.922 workInProgressRoot = null;923 workInProgressRootRenderLanes = NoLanes;924 return workInProgressRootExitStatus;925 } // The work loop is an extremely hot path. Tell Closure not to inline it.926 /** @noinline */927 function workLoopSync() {928 // Already timed out, so perform work without checking if we need to yield.929 while (workInProgress !== null) {930 performUnitOfWork(workInProgress);931 }932 }933 function renderRootConcurrent(root, lanes) {934 var prevExecutionContext = executionContext;935 executionContext |= RenderContext;936 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack937 // and prepare a fresh one. Otherwise we'll continue where we left off.938 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {939 resetRenderTimer();940 prepareFreshStack(root, lanes);941 startWorkOnPendingInteractions(root, lanes);942 }943 var prevInteractions = pushInteractions(root);944 {945 markRenderStarted(lanes);946 }947 do {...

Full Screen

Full Screen

FiberWorkLoop.js

Source:FiberWorkLoop.js Github

copy

Full Screen

...139 let lanes = getNextLanes(140 root,141 root === wipRoot ? wipRootRenderLanes : NoLanes,142 )143 let exitStatus = renderRootConcurrent(root, lanes); 144 if(exitStatus !== RootIncomplete){145 if(exitStatus === RootErrored){146 executionContext |= RootErrored;147 return null;148 }149 // now we have a consistent tree and ready to commit.150 const finishedWork = root.current.alternate151 root.finishedWork = finishedWork;152 root.finishedLanes = lanes;153 finishConcurrentRender(root, exitStatus, lanes);154 }155 //schedule new tasks found in Render Phase156 ensureRootIsScheduled(root, performance.now());157 // root.callbackNode is always relevant to a task which hasn't completely 158 // finished due to expiration or some other reasons and it will be set to 159 // null in Commit Phase.160 if (root.callbackNode === originalCallbackNode){161 return performConcurrentWorkOnRoot.bind(null, root);162 }163 return null;164}165function finishConcurrentRender(root, exitStatus, lanes){166 switch (exitStatus){167 case RootCompleted:{168 commitRoot(root);169 break;170 }171 case RootSuspendedWithDelay:172 case RootSuspended:{ 173 markRootSuspended(root, lanes);174 // work expired. Commit immediately.175 commitRoot(root);176 break;177 }178 }179}180export function pushRenderLanes(fiber, lanes){181 push(subtreeRenderLanesCursor, subtreeRenderLanes);182 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);183 wipRootIncludedLanes = mergeLanes(184 wipRootIncludedLanes,185 lanes,186 );187}188export function popRenderLanes(){189 subtreeRenderLanes = subtreeRenderLanesCursor.current;190 pop(subtreeRenderLanesCursor);191}192function prepareFreshStack(root, lanes){193 if (wip !== null){194 console.error('Leftover work found:', wip);195 }196 wipRoot = root;197 wip = createWorkInProgress(root.current);198 wipRootRenderLanes = subtreeRenderLanes = wipRootIncludedLanes = lanes;199 wipRootExitStatus = RootIncomplete;200 wipRootSkippedLanes = wipRootUpdatedLanes = wipRootPingedLanes = NoLanes;201}202function handleError(root, thrownValue){203 let erroredWork = wip;204 try {205 throwException(206 root,207 erroredWork.return,208 erroredWork,209 thrownValue,210 wipRootRenderLanes211 );212 completeUnitOfWork(erroredWork);213 } catch (yetAnotherThrownValue){214 console.error(yetAnotherThrownValue);215 }216}217export function markSkippedUpdateLanes(lane){218 wipRootSkippedLanes = mergeLanes(219 lane, 220 wipRootSkippedLanes,221 )222}223export function renderDidSuspend(){224 if(wipRootExitStatus === RootIncomplete){225 wipRootExitStatus = RootSuspended;226 }227}228export function renderDidSuspendDelayIfPossible(){229 if(230 wipRootExitStatus === RootIncomplete ||231 wipRootExitStatus === RootSuspended232 ){233 wipRootExitStatus = RootSuspendedWithDelay;234 }235 if(236 wipRoot !== null &&237 (includesNonIdleWork(wipRootSkippedLanes) ||238 includesNonIdleWork(wipRootUpdatedLanes))239 ){240 markRootSuspended(wipRoot, wipRootRenderLanes);241 }242}243export function renderDidError(){244 if (wipRootExitStatus !== RootCompleted){245 wipRootExitStatus = RootErrored;246 }247}248function renderRootConcurrent(root, lanes){249 const prevExecutionContext = executionContext;250 executionContext |= RenderContext;251 // If the root or lanes have changed, throw out the existing stack252 // and prepare a fresh one. Otherwise we'll continue where we left off.253 if (wipRoot !== root || wipRootRenderLanes !== lanes){254 //create a new FiberNode by cloning root.current and set it to wip.255 prepareFreshStack(root, lanes);256 }257 //Keep trying until all caught errors handled.258 do{259 try {260 workLoopConcurrent();261 break;262 } catch(thrownValue){...

Full Screen

Full Screen

SchedulerHostConfig.default.js

Source:SchedulerHostConfig.default.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 */7import {enableIsInputPending} from '../SchedulerFeatureFlags';8export let requestHostCallback;9export let cancelHostCallback;10export let requestHostTimeout;11export let cancelHostTimeout;12export let shouldYieldToHost;13export let requestPaint;14export let getCurrentTime;15export let forceFrameRate;16const hasPerformanceNow =17 typeof performance === 'object' && typeof performance.now === 'function';18if (hasPerformanceNow) {19 const localPerformance = performance;20 // 获取从最开始到现在的时间21 getCurrentTime = () => localPerformance.now();22} else {23 const localDate = Date;24 const initialTime = localDate.now();25 // 获取从最开始到现在的时间26 getCurrentTime = () => localDate.now() - initialTime;27}28if (29 // If Scheduler runs in a non-DOM environment, it falls back to a naive30 // implementation using setTimeout.31 typeof window === 'undefined' ||32 // Check if MessageChannel is supported, too.33 typeof MessageChannel !== 'function'34) {35 // If this accidentally gets imported in a non-browser environment, e.g. JavaScriptCore,36 // fallback to a naive implementation.37 let _callback = null;38 let _timeoutID = null;39 const _flushCallback = function() {40 if (_callback !== null) {41 try {42 const currentTime = getCurrentTime();43 const hasRemainingTime = true;44 _callback(hasRemainingTime, currentTime);45 _callback = null;46 } catch (e) {47 setTimeout(_flushCallback, 0);48 throw e;49 }50 }51 };52 requestHostCallback = function(cb) {53 if (_callback !== null) {54 // Protect against re-entrancy.55 setTimeout(requestHostCallback, 0, cb);56 } else {57 _callback = cb;58 setTimeout(_flushCallback, 0);59 }60 };61 cancelHostCallback = function() {62 _callback = null;63 };64 requestHostTimeout = function(cb, ms) {65 _timeoutID = setTimeout(cb, ms);66 };67 cancelHostTimeout = function() {68 clearTimeout(_timeoutID);69 };70 shouldYieldToHost = function() {71 return false;72 };73 requestPaint = forceFrameRate = function() {};74} else {75 // Capture local references to native APIs, in case a polyfill overrides them.76 // fiber架构异步更新依赖浏览器原生api window.requestAnimationFrame window.cancelAnimationFrame77 const setTimeout = window.setTimeout;78 const clearTimeout = window.clearTimeout;79 if (typeof console !== 'undefined') {80 // TODO: Scheduler no longer requires these methods to be polyfilled. But81 // maybe we want to continue warning if they don't exist, to preserve the82 // option to rely on it in the future?83 const requestAnimationFrame = window.requestAnimationFrame;84 const cancelAnimationFrame = window.cancelAnimationFrame;85 if (typeof requestAnimationFrame !== 'function') {86 // Using console['error'] to evade Babel and ESLint87 console['error'](88 "This browser doesn't support requestAnimationFrame. " +89 'Make sure that you load a ' +90 'polyfill in older browsers. https://reactjs.org/link/react-polyfills',91 );92 }93 if (typeof cancelAnimationFrame !== 'function') {94 // Using console['error'] to evade Babel and ESLint95 console['error'](96 "This browser doesn't support cancelAnimationFrame. " +97 'Make sure that you load a ' +98 'polyfill in older browsers. https://reactjs.org/link/react-polyfills',99 );100 }101 }102 let isMessageLoopRunning = false;103 let scheduledHostCallback = null;104 let taskTimeoutID = -1;105 // Scheduler periodically yields in case there is other work on the main106 // thread, like user events. By default, it yields multiple times per frame.107 // It does not attempt to align with frame boundaries, since most tasks don't108 // need to be frame aligned; for those that do, use requestAnimationFrame.109 // 每帧的时间设置为5ms110 let yieldInterval = 5;111 let deadline = 0;112 // TODO: Make this configurable113 // TODO: Adjust this based on priority?114 const maxYieldInterval = 300;115 let needsPaint = false;116 // 兼容性处理navigator.scheduling117 // 设置shouldYieldToHost和requestPaint118 if (119 enableIsInputPending &&120 navigator !== undefined &&121 navigator.scheduling !== undefined &&122 navigator.scheduling.isInputPending !== undefined123 ) {124 const scheduling = navigator.scheduling;125 // 是否需要移交控制给浏览器126 // 超时/需要重绘为true,否则为false127 shouldYieldToHost = function() {128 const currentTime = getCurrentTime();129 if (currentTime >= deadline) {130 // There's no time left. We may want to yield control of the main131 // thread, so the browser can perform high priority tasks. The main ones132 // are painting and user input. If there's a pending paint or a pending133 // input, then we should yield. But if there's neither, then we can134 // yield less often while remaining responsive. We'll eventually yield135 // regardless, since there could be a pending paint that wasn't136 // accompanied by a call to `requestPaint`, or other main thread tasks137 // like network events.138 if (needsPaint || scheduling.isInputPending()) {139 // There is either a pending paint or a pending input.140 return true;141 }142 // There's no pending input. Only yield if we've reached the max143 // yield interval.144 return currentTime >= maxYieldInterval;145 } else {146 // There's still time left in the frame.147 return false;148 }149 };150 requestPaint = function() {151 needsPaint = true;152 };153 } else {154 // `isInputPending` is not available. Since we have no way of knowing if155 // there's pending input, always yield at the end of the frame.156 shouldYieldToHost = function() {157 return getCurrentTime() >= deadline;158 };159 // Since we yield every frame regardless, `requestPaint` has no effect.160 requestPaint = function() {};161 }162 // fps只支持0到125163 forceFrameRate = function(fps) {164 if (fps < 0 || fps > 125) {165 // Using console['error'] to evade Babel and ESLint166 console['error'](167 'forceFrameRate takes a positive int between 0 and 125, ' +168 'forcing frame rates higher than 125 fps is not supported',169 );170 return;171 }172 if (fps > 0) {173 yieldInterval = Math.floor(1000 / fps);174 } else {175 // reset the framerate176 yieldInterval = 5;177 }178 };179 // 这里会循环执行 scheduledHostCallback => flushWork => workLoop,直到异步更新完taskQueue中的所有任务180 const performWorkUntilDeadline = () => {181 if (scheduledHostCallback !== null) {182 const currentTime = getCurrentTime();183 // Yield after `yieldInterval` ms, regardless of where we are in the vsync184 // cycle. This means there's always time remaining at the beginning of185 // the message event.186 // 当前时间(从最开始到现在的时间) 加上 每帧留给react的时间(一般为5ms),即为超时时间187 // 也就是定义超时时间deadline为当前的基础上加上 每帧留给react的时间(一般为5ms)188 // 这个超时时间用在shouldYieldToHost中,用于判断是否需要移交控制给浏览器189 deadline = currentTime + yieldInterval;190 const hasTimeRemaining = true;191 try {192 // taskQueue被中断的话,这里为true,否则为false193 const hasMoreWork = scheduledHostCallback(194 hasTimeRemaining,195 currentTime,196 );197 if (!hasMoreWork) {198 // taskQueue中没有任务,标记isMessageLoopRunning为false,重置scheduledHostCallback为null,结束循环199 isMessageLoopRunning = false;200 scheduledHostCallback = null;201 } else {202 // If there's more work, schedule the next message event at the end203 // of the preceding one.204 // taskQueue被中断,继续触发performWorkUntilDeadline205 // 这里会一直调用 scheduledHostCallback => flushWork => workLoop,直到异步更新完taskQueue中的所有任务206 // 具体流程207 // performWorkUntilDeadline => scheduledHostCallback(也就是flushWork)208 // => workLoop(遍历执行taskQueue中的任务,也就是performConcurrentWorkOnRoot)209 // => renderRootConcurrent => workLoopConcurrent(这里就会判断是否需要移交控制权,然后决定是否执行performUnitOfWork)210 // => 如果中断,taskQueue中的performConcurrentWorkOnRoot对应的task任务不会清除,同时跳出更新,返回true到hasMoreWork => port.postMessage(null) 宏任务 => 触发下一次performWorkUntilDeadline => ...211 // 如果没有中断,返回false到hasMoreWork,结束taskQueue中的更新。如果有timeQueue,会在延时到了之后推入taskQueue开始更新212 port.postMessage(null);213 }214 } catch (error) {215 // If a scheduler task throws, exit the current browser task so the216 // error can be observed.217 port.postMessage(null);218 throw error;219 }220 } else {221 // 没有scheduledHostCallback,标记isMessageLoopRunning为false,结束循环222 isMessageLoopRunning = false;223 }224 // Yielding to the browser will give it a chance to paint, so we can225 // reset this.226 // 这里设置needsPaint为false,这个needsPaint用在shouldYieldToHost中,用于判断是否需要移交控制给浏览器227 needsPaint = false;228 };229 // 创建一个新的消息通道,并通过它的两个MessagePort属性发送数据230 // 宏任务231 const channel = new MessageChannel();232 const port = channel.port2;233 // onmessage的执行实际很重要234 // react给单次performWorkUntilDeadline的时间只有5ms,一旦超过5ms,必须移交控制权给浏览器,浏览器处理requestAnimationFrame、页面渲染绘制235 // 等到浏览器自己的工作完成了,会执行宏任务,也就是下一个performWorkUntilDeadline236 // react用这种方式模拟了requestIdleCallback(由于兼容性问题没有采用)237 // 保证给浏览器单帧的工作时间理论上是 1000/60-5=11.67ms(60Hz刷新率)238 // 但是无法保证单次performWorkUntilDeadline中的最后一个单元任务的结束时间会超过5ms多久,理论上切成单元任务之后不会超出5ms很多239 // 而留给浏览器的11.67ms其实是有余量的(浏览器不需要这么久),所有理论上是不会造成页面卡顿240 channel.port1.onmessage = performWorkUntilDeadline;241 // 设置requestHostCallback,并触发performWorkUntilDeadline242 requestHostCallback = function(callback) {243 scheduledHostCallback = callback;244 if (!isMessageLoopRunning) {245 isMessageLoopRunning = true;246 port.postMessage(null);247 }248 };249 cancelHostCallback = function() {250 scheduledHostCallback = null;251 };252 // 设置taskTimeoutID,延时ms后执行callback253 requestHostTimeout = function(callback, ms) {254 taskTimeoutID = setTimeout(() => {255 callback(getCurrentTime());256 }, ms);257 };258 cancelHostTimeout = function() {259 clearTimeout(taskTimeoutID);260 taskTimeoutID = -1;261 };...

Full Screen

Full Screen

env.js

Source:env.js Github

copy

Full Screen

1const fs = require('fs');2const path = require('path');3const paths = require('./paths');4// Make sure that including paths.js after env.js will read .env variables.5delete require.cache[require.resolve('./paths')];6const NODE_ENV = process.env.NODE_ENV;7if (!NODE_ENV) {8 throw new Error(9 'The NODE_ENV environment variable is required but was not specified.'10 );11}12// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use13const dotenvFiles = [14 `${paths.dotenv}.${NODE_ENV}.local`,15 `${paths.dotenv}.${NODE_ENV}`,16 // Don't include `.env.local` for `test` environment17 // since normally you expect tests to produce the same18 // results for everyone19 NODE_ENV !== 'test' && `${paths.dotenv}.local`,20 paths.dotenv,21].filter(Boolean);22// Load environment variables from .env* files. Suppress warnings using silent23// if this file is missing. dotenv will never modify any environment variables24// that have already been set. Variable expansion is supported in .env files.25// https://github.com/motdotla/dotenv26// https://github.com/motdotla/dotenv-expand27dotenvFiles.forEach(dotenvFile => {28 if (fs.existsSync(dotenvFile)) {29 require('dotenv-expand')(30 require('dotenv').config({31 path: dotenvFile,32 })33 );34 }35});36// We support resolving modules according to `NODE_PATH`.37// This lets you use absolute paths in imports inside large monorepos:38// https://github.com/facebook/create-react-app/issues/253.39// It works similar to `NODE_PATH` in Node itself:40// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders41// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.42// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.43// https://github.com/facebook/create-react-app/issues/1023#issuecomment-26534442144// We also resolve them to make sure all tools using them work consistently.45const appDirectory = fs.realpathSync(process.cwd());46process.env.NODE_PATH = (process.env.NODE_PATH || '')47 .split(path.delimiter)48 .filter(folder => folder && !path.isAbsolute(folder))49 .map(folder => path.resolve(appDirectory, folder))50 .join(path.delimiter);51// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be52// injected into the application via DefinePlugin in webpack configuration.53const REACT_APP = /^REACT_APP_/i;54function getClientEnvironment(publicUrl) {55 const raw = Object.keys(process.env)56 .filter(key => REACT_APP.test(key))57 .reduce(58 (env, key) => {59 env[key] = process.env[key];60 return env;61 },62 {63 // Useful for determining whether we’re running in production mode.64 // Most importantly, it switches React into the correct mode.65 NODE_ENV: process.env.NODE_ENV || 'development',66 // Useful for resolving the correct path to static assets in `public`.67 // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.68 // This should only be used as an escape hatch. Normally you would put69 // images into the `src` and `import` them in code to get their paths.70 PUBLIC_URL: publicUrl,71 // We support configuring the sockjs pathname during development.72 // These settings let a developer run multiple simultaneous projects.73 // They are used as the connection `hostname`, `pathname` and `port`74 // in webpackHotDevClient. They are used as the `sockHost`, `sockPath`75 // and `sockPort` options in webpack-dev-server.76 WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,77 WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,78 WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,79 }80 );81 // Stringify all values so we can feed into webpack DefinePlugin82 const stringified = {83 'process.env': Object.keys(raw).reduce((env, key) => {84 env[key] = JSON.stringify(raw[key]);85 return env;86 }, {}),87 "__DEV__": false,88 "__PROFILE__": true,89 "__EXPERIMENTAL__": true,90 "__UMD__": true,91 __NEW_RECONCILER__: true,92 '__LOG_NAMES__': JSON.stringify([93 // 'createRoot',94 // 'ReactDOMRoot',95 // 'createRootImpl',96 // 'createContainer',97 // 'createFiberRoot',98 // 'createHostRootFiber',99 // 'createFiber',100 // 'FiberNode',101 // 'initializeUpdateQueue',102 // 'markContainerAsRoot',103 // 'listenToAllSupportedEvents',104 // 'jsx',105 'render',106 // 'updateContainer',107 // 'enqueueUpdate',108 // 'scheduleUpdateOnFiber',109 // 'ensureRootIsScheduled',110 // 'unstable_scheduleCallback',111 // 'requestHostCallback',112 // 'performWorkUntilDeadline',113 // 'flushWork',114 // 'workLoop',115 // 'performConcurrentWorkOnRoot',116 // 'flushPassiveEffects',117 // 'renderRootConcurrent',118 // 'prepareFreshStack',119 // 'createWorkInProgress',120 // 'createFiber',121 // 'FiberNode',122 // 'performUnitOfWork',123 // 'beginWork',124 // 'setInitialDOMProperties',125 // 'setInitialProperties',126 // 'diffProperties',127 // 'dispatchEvent',128 // 'mountIndeterminateComponent',129 // 'renderWithHooks',130 'useState',131 // 'mountState',132 // 'mountWorkInProgressHook',133 // 'updateHostRoot',134 // 'cloneUpdateQueue',135 // 'processUpdateQueue',136 // 'getStateFromUpdate',137 // 'reconcileChildren',138 // 'reconcileChildFibers',139 // 'reconcileChildrenArray',140 // 'createChild',141 // 'mountChildFibers',142 // 'createFiberFromElement',143 // 'createFiberFromTypeAndProps',144 // 'completeUnitOfWork',145 // 'completeWork',146 // 'commitRootImpl',147 // 'commitBeforeMutationEffects',148 // 'commitBeforeMutationEffectsImpl',149 // 'commitBeforeMutationLifeCycles',150 // 'clearContainer',151 // 'commitMutationEffectsImpl',152 // 'commitPlacement',153 // 'getHostParentFiber',154 // 'getHostSibling',155 // 'insertOrAppendPlacementNodeIntoContainer',156 // 'insertOrAppendPlacementNode',157 // 'trapClickOnNonInteractiveElement',158 // 'resetAfterCommit',159 // 'restoreSelection',160 // 'recursivelyCommitLayoutEffects',161 // 'ensureRootIsScheduled',162 // 'createInstance',163 // 'createElement',164 // 'updateFiberProps',165 // 'bubbleProperties',166 // 'dispatchDiscreteEvent',167 // 'createEventListenerWrapperWithPriority',168 'updateWorkInProgressHook'169 ]),170 };171 return { raw, stringified };172}...

Full Screen

Full Screen

render.js

Source:render.js Github

copy

Full Screen

...24///////////////////////////// 25// 在Fiber上并发执行26function performConcurrentWorkOnRoot() {27 // render 阶段28 renderRootConcurrent();29 // commit 阶段30 commitRoot(root)31}32function renderRootConcurrent() {33 do {34 try {35 workLoopConcurrent();36 break;37 } catch (thrownValue) {38 handleError(root, thrownValue);39 }40 } while (true);41}42function workLoopConcurrent() {43 while (workInProgress !== null && !shouldYield()) {44 performUnitOfWork(workInProgress);45 }46}...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const html = await page.renderRootConcurrent();7 console.log(html);8 await browser.close();9})();10import { chromium } from 'playwright';11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 const html = await page.renderRootConcurrent();16 console.log(html);17 await browser.close();18})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const page = await browser.newPage();5 await page.renderRootConcurrent();6 await browser.close();7})();8const playwright = require('playwright');9(async () => {10 const browser = await playwright.chromium.launch();11 const page = await browser.newPage();12 await page.renderRootConcurrent('screenshot.png');13 await browser.close();14})();15const playwright = require('playwright');16(async () => {17 const browser = await playwright.chromium.launch();18 const page = await browser.newPage();19 await page.renderRootConcurrent('screenshot.png');20 await browser.close();21})();22const playwright = require('playwright');23(async () => {24 const browser = await playwright.chromium.launch();25 const page = await browser.newPage();26 await page.renderRootConcurrent('screenshot.png');27 await browser.close();28})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const page = await browser.newPage();5 const content = await page.renderRootConcurrent();6 console.log(content);7 await browser.close();8})();9const playwright = require('playwright');10(async () => {11 const browser = await playwright.chromium.launch();12 const page = await browser.newPage();13 const content = await page.renderRoot();14 console.log(content);15 await browser.close();16})();17const playwright = require('playwright');18(async () => {19 const browser = await playwright.chromium.launch();20 const page = await browser.newPage();21 const content = await page.render();22 console.log(content);23 await browser.close();24})();25const playwright = require('playwright');26(async () => {27 const browser = await playwright.chromium.launch();28 const page = await browser.newPage();29 const content = await page.render();30 console.log(content);31 await browser.close();32})();33const playwright = require('playwright');34(async () => {35 const browser = await playwright.chromium.launch();36 const page = await browser.newPage();37 const content = await page.render();38 console.log(content);39 await browser.close();40})();41const playwright = require('playwright');42(async () => {43 const browser = await playwright.chromium.launch();44 const page = await browser.newPage();45 const content = await page.render();46 console.log(content);47 await browser.close();48})();49const playwright = require('playwright');50(async () => {51 const browser = await playwright.chromium.launch();52 const page = await browser.newPage();53 const content = await page.render();54 console.log(content);55 await browser.close();56})();57const playwright = require('playwright');58(async () => {

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext({ headless: false });5 const page = await context.newPage();6 const { html } = await page.renderRootConcurrent();7 console.log(html);8 await browser.close();9})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');3const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');4const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');5const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');6const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');7const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');8const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');9const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');10const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');11const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');12const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');13const { renderRootConcurrent } = require('playwright/lib/server/supplements/recorder/recorderSupplement');14const { renderRoot

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2const playwright = require('playwright/lib/server/playwright');3const { renderRootConcurrent } = playwright;4(async () => {5 const browser = await chromium.launch({6 });7 const context = await browser.newContext();8 const page = await context.newPage();9 const root = await page.document();10 const element = await root.querySelector('h1');11 const result = await renderRootConcurrent(root);12 console.log(result);13 await browser.close();14})();15const { chromium } = require('playwright');16const playwright = require('playwright/lib/server/playwright');17const { renderRootConcurrent } = playwright;18(async () => {19 const browser = await chromium.launch({20 });21 const context = await browser.newContext();22 const page = await context.newPage();23 const root = await page.document();24 const element = await root.querySelector('h1');25 const result = await renderRootConcurrent(root);26 console.log(result);27 await browser.close();28})();

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful