Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js
...305// suspense heuristics and opt out of rendering more content.306const RENDER_TIMEOUT_MS = 500;307// Used to avoid traversing the return path to find the nearest Profiler ancestor during commit.308let nearestProfilerOnStack: Fiber | null = null;309function resetRenderTimer() {310 workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;311}312export function getRenderTargetTime(): number {313 return workInProgressRootRenderTargetTime;314}315let hasUncaughtError = false;316let firstUncaughtError = null;317let legacyErrorBoundariesThatAlreadyFailed: Set<mixed> | null = null;318let rootDoesHavePassiveEffects: boolean = false;319let rootWithPendingPassiveEffects: FiberRoot | null = null;320let pendingPassiveEffectsRenderPriority: ReactPriorityLevel = NoSchedulerPriority;321let pendingPassiveEffectsLanes: Lanes = NoLanes;322let rootsWithPendingDiscreteUpdates: Set<FiberRoot> | null = null;323// Use these to prevent an infinite loop of nested updates324const NESTED_UPDATE_LIMIT = 50;325let nestedUpdateCount: number = 0;326let rootWithNestedUpdates: FiberRoot | null = null;327const NESTED_PASSIVE_UPDATE_LIMIT = 50;328let nestedPassiveUpdateCount: number = 0;329// Marks the need to reschedule pending interactions at these lanes330// during the commit phase. This enables them to be traced across components331// that spawn new work during render. E.g. hidden boundaries, suspended SSR332// hydration or SuspenseList.333// TODO: Can use a bitmask instead of an array334let spawnedWorkDuringRender: null | Array<Lane | Lanes> = null;335// If two updates are scheduled within the same event, we should treat their336// event times as simultaneous, even if the actual clock time has advanced337// between the first and second call.338let currentEventTime: number = NoTimestamp;339let currentEventWipLanes: Lanes = NoLanes;340let currentEventPendingLanes: Lanes = NoLanes;341// Dev only flag that tracks if passive effects are currently being flushed.342// We warn about state updates for unmounted components differently in this case.343let isFlushingPassiveEffects = false;344let focusedInstanceHandle: null | Fiber = null;345let shouldFireAfterActiveInstanceBlur: boolean = false;346export function getWorkInProgressRoot(): FiberRoot | null {347 return workInProgressRoot;348}349export function requestEventTime() {350 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {351 // We're inside React, so it's fine to read the actual time.352 return now();353 }354 // We're not inside React, so we may be in the middle of a browser event.355 if (currentEventTime !== NoTimestamp) {356 // Use the same start time for all updates until we enter React again.357 return currentEventTime;358 }359 // This is the first update since React yielded. Compute a new start time.360 currentEventTime = now();361 return currentEventTime;362}363export function getCurrentTime() {364 return now();365}366export function requestUpdateLane(fiber: Fiber): Lane {367 // Special cases368 const mode = fiber.mode;369 if ((mode & BlockingMode) === NoMode) {370 return (SyncLane: Lane);371 } else if ((mode & ConcurrentMode) === NoMode) {372 return getCurrentPriorityLevel() === ImmediateSchedulerPriority373 ? (SyncLane: Lane)374 : (SyncBatchedLane: Lane);375 } else if (376 !deferRenderPhaseUpdateToNextBatch &&377 (executionContext & RenderContext) !== NoContext &&378 workInProgressRootRenderLanes !== NoLanes379 ) {380 // This is a render phase update. These are not officially supported. The381 // old behavior is to give this the same "thread" (expiration time) as382 // whatever is currently rendering. So if you call `setState` on a component383 // that happens later in the same render, it will flush. Ideally, we want to384 // remove the special case and treat them as if they came from an385 // interleaved event. Regardless, this pattern is not officially supported.386 // This behavior is only a fallback. The flag only exists until we can roll387 // out the setState warning, since existing code might accidentally rely on388 // the current behavior.389 return pickArbitraryLane(workInProgressRootRenderLanes);390 }391 // The algorithm for assigning an update to a lane should be stable for all392 // updates at the same priority within the same event. To do this, the inputs393 // to the algorithm must be the same. For example, we use the `renderLanes`394 // to avoid choosing a lane that is already in the middle of rendering.395 //396 // However, the "included" lanes could be mutated in between updates in the397 // same event, like if you perform an update inside `flushSync`. Or any other398 // code path that might call `prepareFreshStack`.399 //400 // The trick we use is to cache the first of each of these inputs within an401 // event. Then reset the cached values once we can be sure the event is over.402 // Our heuristic for that is whenever we enter a concurrent work loop.403 //404 // We'll do the same for `currentEventPendingLanes` below.405 if (currentEventWipLanes === NoLanes) {406 currentEventWipLanes = workInProgressRootIncludedLanes;407 }408 const isTransition = requestCurrentTransition() !== NoTransition;409 if (isTransition) {410 if (currentEventPendingLanes !== NoLanes) {411 currentEventPendingLanes =412 mostRecentlyUpdatedRoot !== null413 ? mostRecentlyUpdatedRoot.pendingLanes414 : NoLanes;415 }416 return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);417 }418 // TODO: Remove this dependency on the Scheduler priority.419 // To do that, we're replacing it with an update lane priority.420 const schedulerPriority = getCurrentPriorityLevel();421 // The old behavior was using the priority level of the Scheduler.422 // This couples React to the Scheduler internals, so we're replacing it423 // with the currentUpdateLanePriority above. As an example of how this424 // could be problematic, if we're not inside `Scheduler.runWithPriority`,425 // then we'll get the priority of the current running Scheduler task,426 // which is probably not what we want.427 let lane;428 if (429 // TODO: Temporary. We're removing the concept of discrete updates.430 (executionContext & DiscreteEventContext) !== NoContext &&431 schedulerPriority === UserBlockingSchedulerPriority432 ) {433 lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);434 } else {435 const schedulerLanePriority = schedulerPriorityToLanePriority(436 schedulerPriority,437 );438 if (decoupleUpdatePriorityFromScheduler) {439 // In the new strategy, we will track the current update lane priority440 // inside React and use that priority to select a lane for this update.441 // For now, we're just logging when they're different so we can assess.442 const currentUpdateLanePriority = getCurrentUpdateLanePriority();443 if (444 schedulerLanePriority !== currentUpdateLanePriority &&445 currentUpdateLanePriority !== NoLanePriority446 ) {447 if (__DEV__) {448 console.error(449 'Expected current scheduler lane priority %s to match current update lane priority %s',450 schedulerLanePriority,451 currentUpdateLanePriority,452 );453 }454 }455 }456 lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);457 }458 return lane;459}460function requestRetryLane(fiber: Fiber) {461 // This is a fork of `requestUpdateLane` designed specifically for Suspense462 // "retries" â a special update that attempts to flip a Suspense boundary463 // from its placeholder state to its primary/resolved state.464 // Special cases465 const mode = fiber.mode;466 if ((mode & BlockingMode) === NoMode) {467 return (SyncLane: Lane);468 } else if ((mode & ConcurrentMode) === NoMode) {469 return getCurrentPriorityLevel() === ImmediateSchedulerPriority470 ? (SyncLane: Lane)471 : (SyncBatchedLane: Lane);472 }473 // See `requestUpdateLane` for explanation of `currentEventWipLanes`474 if (currentEventWipLanes === NoLanes) {475 currentEventWipLanes = workInProgressRootIncludedLanes;476 }477 return findRetryLane(currentEventWipLanes);478}479export function scheduleUpdateOnFiber(480 fiber: Fiber,481 lane: Lane,482 eventTime: number,483) {484 checkForNestedUpdates();485 warnAboutRenderPhaseUpdatesInDEV(fiber);486 const root = markUpdateLaneFromFiberToRoot(fiber, lane);487 if (root === null) {488 warnAboutUpdateOnUnmountedFiberInDEV(fiber);489 return null;490 }491 // Mark that the root has a pending update.492 markRootUpdated(root, lane, eventTime);493 if (root === workInProgressRoot) {494 // Received an update to a tree that's in the middle of rendering. Mark495 // that there was an interleaved update work on this root. Unless the496 // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render497 // phase update. In that case, we don't treat render phase updates as if498 // they were interleaved, for backwards compat reasons.499 if (500 deferRenderPhaseUpdateToNextBatch ||501 (executionContext & RenderContext) === NoContext502 ) {503 workInProgressRootUpdatedLanes = mergeLanes(504 workInProgressRootUpdatedLanes,505 lane,506 );507 }508 if (workInProgressRootExitStatus === RootSuspendedWithDelay) {509 // The root already suspended with a delay, which means this render510 // definitely won't finish. Since we have a new update, let's mark it as511 // suspended now, right before marking the incoming update. This has the512 // effect of interrupting the current render and switching to the update.513 // TODO: Make sure this doesn't override pings that happen while we've514 // already started rendering.515 markRootSuspended(root, workInProgressRootRenderLanes);516 }517 }518 // TODO: requestUpdateLanePriority also reads the priority. Pass the519 // priority as an argument to that function and this one.520 const priorityLevel = getCurrentPriorityLevel();521 if (lane === SyncLane) {522 if (523 // Check if we're inside unbatchedUpdates524 (executionContext & LegacyUnbatchedContext) !== NoContext &&525 // Check if we're not already rendering526 (executionContext & (RenderContext | CommitContext)) === NoContext527 ) {528 // Register pending interactions on the root to avoid losing traced interaction data.529 schedulePendingInteractions(root, lane);530 // This is a legacy edge case. The initial mount of a ReactDOM.render-ed531 // root inside of batchedUpdates should be synchronous, but layout updates532 // should be deferred until the end of the batch.533 performSyncWorkOnRoot(root);534 } else {535 ensureRootIsScheduled(root, eventTime);536 schedulePendingInteractions(root, lane);537 if (executionContext === NoContext) {538 // Flush the synchronous work now, unless we're already working or inside539 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of540 // scheduleCallbackForFiber to preserve the ability to schedule a callback541 // without immediately flushing it. We only do this for user-initiated542 // updates, to preserve historical behavior of legacy mode.543 resetRenderTimer();544 flushSyncCallbackQueue();545 }546 }547 } else {548 // Schedule a discrete update but only if it's not Sync.549 if (550 (executionContext & DiscreteEventContext) !== NoContext &&551 // Only updates at user-blocking priority or greater are considered552 // discrete, even inside a discrete event.553 (priorityLevel === UserBlockingSchedulerPriority ||554 priorityLevel === ImmediateSchedulerPriority)555 ) {556 // This is the result of a discrete event. Track the lowest priority557 // discrete update per root so we can flush them early, if needed.558 if (rootsWithPendingDiscreteUpdates === null) {559 rootsWithPendingDiscreteUpdates = new Set([root]);560 } else {561 rootsWithPendingDiscreteUpdates.add(root);562 }563 }564 // Schedule other updates after in case the callback is sync.565 ensureRootIsScheduled(root, eventTime);566 schedulePendingInteractions(root, lane);567 }568 // We use this when assigning a lane for a transition inside569 // `requestUpdateLane`. We assume it's the same as the root being updated,570 // since in the common case of a single root app it probably is. If it's not571 // the same root, then it's not a huge deal, we just might batch more stuff572 // together more than necessary.573 mostRecentlyUpdatedRoot = root;574}575// This is split into a separate function so we can mark a fiber with pending576// work without treating it as a typical update that originates from an event;577// e.g. retrying a Suspense boundary isn't an update, but it does schedule work578// on a fiber.579function markUpdateLaneFromFiberToRoot(580 sourceFiber: Fiber,581 lane: Lane,582): FiberRoot | null {583 // Update the source fiber's lanes584 sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);585 let alternate = sourceFiber.alternate;586 if (alternate !== null) {587 alternate.lanes = mergeLanes(alternate.lanes, lane);588 }589 if (__DEV__) {590 if (591 alternate === null &&592 (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags593 ) {594 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);595 }596 }597 // Walk the parent path to the root and update the child expiration time.598 let node = sourceFiber;599 let parent = sourceFiber.return;600 while (parent !== null) {601 parent.childLanes = mergeLanes(parent.childLanes, lane);602 alternate = parent.alternate;603 if (alternate !== null) {604 alternate.childLanes = mergeLanes(alternate.childLanes, lane);605 } else {606 if (__DEV__) {607 if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {608 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);609 }610 }611 }612 node = parent;613 parent = parent.return;614 }615 if (node.tag === HostRoot) {616 const root: FiberRoot = node.stateNode;617 return root;618 } else {619 return null;620 }621}622// Use this function to schedule a task for a root. There's only one task per623// root; if a task was already scheduled, we'll check to make sure the priority624// of the existing task is the same as the priority of the next level that the625// root has work on. This function is called on every update, and right before626// exiting a task.627function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {628 const existingCallbackNode = root.callbackNode;629 // Check if any lanes are being starved by other work. If so, mark them as630 // expired so we know to work on those next.631 markStarvedLanesAsExpired(root, currentTime);632 // Determine the next lanes to work on, and their priority.633 const nextLanes = getNextLanes(634 root,635 root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,636 );637 // This returns the priority level computed during the `getNextLanes` call.638 const newCallbackPriority = returnNextLanesPriority();639 if (nextLanes === NoLanes) {640 // Special case: There's nothing to work on.641 if (existingCallbackNode !== null) {642 cancelCallback(existingCallbackNode);643 root.callbackNode = null;644 root.callbackPriority = NoLanePriority;645 }646 return;647 }648 // Check if there's an existing task. We may be able to reuse it.649 if (existingCallbackNode !== null) {650 const existingCallbackPriority = root.callbackPriority;651 if (existingCallbackPriority === newCallbackPriority) {652 // The priority hasn't changed. We can reuse the existing task. Exit.653 return;654 }655 // The priority changed. Cancel the existing callback. We'll schedule a new656 // one below.657 cancelCallback(existingCallbackNode);658 }659 // Schedule a new callback.660 let newCallbackNode;661 if (newCallbackPriority === SyncLanePriority) {662 // Special case: Sync React callbacks are scheduled on a special663 // internal queue664 newCallbackNode = scheduleSyncCallback(665 performSyncWorkOnRoot.bind(null, root),666 );667 } else if (newCallbackPriority === SyncBatchedLanePriority) {668 newCallbackNode = scheduleCallback(669 ImmediateSchedulerPriority,670 performSyncWorkOnRoot.bind(null, root),671 );672 } else {673 const schedulerPriorityLevel = lanePriorityToSchedulerPriority(674 newCallbackPriority,675 );676 newCallbackNode = scheduleCallback(677 schedulerPriorityLevel,678 performConcurrentWorkOnRoot.bind(null, root),679 );680 }681 root.callbackPriority = newCallbackPriority;682 root.callbackNode = newCallbackNode;683}684// This is the entry point for every concurrent task, i.e. anything that685// goes through Scheduler.686function performConcurrentWorkOnRoot(root) {687 // Since we know we're in a React event, we can clear the current688 // event time. The next update will compute a new event time.689 currentEventTime = NoTimestamp;690 currentEventWipLanes = NoLanes;691 currentEventPendingLanes = NoLanes;692 invariant(693 (executionContext & (RenderContext | CommitContext)) === NoContext,694 'Should not already be working.',695 );696 // Flush any pending passive effects before deciding which lanes to work on,697 // in case they schedule additional work.698 const originalCallbackNode = root.callbackNode;699 const didFlushPassiveEffects = flushPassiveEffects();700 if (didFlushPassiveEffects) {701 // Something in the passive effect phase may have canceled the current task.702 // Check if the task node for this root was changed.703 if (root.callbackNode !== originalCallbackNode) {704 // The current task was canceled. Exit. We don't need to call705 // `ensureRootIsScheduled` because the check above implies either that706 // there's a new task, or that there's no remaining work on this root.707 return null;708 } else {709 // Current task was not canceled. Continue.710 }711 }712 // Determine the next expiration time to work on, using the fields stored713 // on the root.714 let lanes = getNextLanes(715 root,716 root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,717 );718 if (lanes === NoLanes) {719 // Defensive coding. This is never expected to happen.720 return null;721 }722 let exitStatus = renderRootConcurrent(root, lanes);723 if (724 includesSomeLane(725 workInProgressRootIncludedLanes,726 workInProgressRootUpdatedLanes,727 )728 ) {729 // The render included lanes that were updated during the render phase.730 // For example, when unhiding a hidden tree, we include all the lanes731 // that were previously skipped when the tree was hidden. That set of732 // lanes is a superset of the lanes we started rendering with.733 //734 // So we'll throw out the current work and restart.735 prepareFreshStack(root, NoLanes);736 } else if (exitStatus !== RootIncomplete) {737 if (exitStatus === RootErrored) {738 executionContext |= RetryAfterError;739 // If an error occurred during hydration,740 // discard server response and fall back to client side render.741 if (root.hydrate) {742 root.hydrate = false;743 clearContainer(root.containerInfo);744 }745 // If something threw an error, try rendering one more time. We'll render746 // synchronously to block concurrent data mutations, and we'll includes747 // all pending updates are included. If it still fails after the second748 // attempt, we'll give up and commit the resulting tree.749 lanes = getLanesToRetrySynchronouslyOnError(root);750 if (lanes !== NoLanes) {751 exitStatus = renderRootSync(root, lanes);752 }753 }754 if (exitStatus === RootFatalErrored) {755 const fatalError = workInProgressRootFatalError;756 prepareFreshStack(root, NoLanes);757 markRootSuspended(root, lanes);758 ensureRootIsScheduled(root, now());759 throw fatalError;760 }761 // We now have a consistent tree. The next step is either to commit it,762 // or, if something suspended, wait to commit it after a timeout.763 const finishedWork: Fiber = (root.current.alternate: any);764 root.finishedWork = finishedWork;765 root.finishedLanes = lanes;766 finishConcurrentRender(root, exitStatus, lanes);767 }768 ensureRootIsScheduled(root, now());769 if (root.callbackNode === originalCallbackNode) {770 // The task node scheduled for this root is the same one that's771 // currently executed. Need to return a continuation.772 return performConcurrentWorkOnRoot.bind(null, root);773 }774 return null;775}776function finishConcurrentRender(root, exitStatus, lanes) {777 switch (exitStatus) {778 case RootIncomplete:779 case RootFatalErrored: {780 invariant(false, 'Root did not complete. This is a bug in React.');781 }782 // Flow knows about invariant, so it complains if I add a break783 // statement, but eslint doesn't know about invariant, so it complains784 // if I do. eslint-disable-next-line no-fallthrough785 case RootErrored: {786 // We should have already attempted to retry this tree. If we reached787 // this point, it errored again. Commit it.788 commitRoot(root);789 break;790 }791 case RootSuspended: {792 markRootSuspended(root, lanes);793 // We have an acceptable loading state. We need to figure out if we794 // should immediately commit it or wait a bit.795 if (796 includesOnlyRetries(lanes) &&797 // do not delay if we're inside an act() scope798 !shouldForceFlushFallbacksInDEV()799 ) {800 // This render only included retries, no updates. Throttle committing801 // retries so that we don't show too many loading states too quickly.802 const msUntilTimeout =803 globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();804 // Don't bother with a very short suspense time.805 if (msUntilTimeout > 10) {806 const nextLanes = getNextLanes(root, NoLanes);807 if (nextLanes !== NoLanes) {808 // There's additional work on this root.809 break;810 }811 const suspendedLanes = root.suspendedLanes;812 if (!isSubsetOfLanes(suspendedLanes, lanes)) {813 // We should prefer to render the fallback of at the last814 // suspended level. Ping the last suspended level to try815 // rendering it again.816 // FIXME: What if the suspended lanes are Idle? Should not restart.817 const eventTime = requestEventTime();818 markRootPinged(root, suspendedLanes, eventTime);819 break;820 }821 // The render is suspended, it hasn't timed out, and there's no822 // lower priority work to do. Instead of committing the fallback823 // immediately, wait for more data to arrive.824 root.timeoutHandle = scheduleTimeout(825 commitRoot.bind(null, root),826 msUntilTimeout,827 );828 break;829 }830 }831 // The work expired. Commit immediately.832 commitRoot(root);833 break;834 }835 case RootSuspendedWithDelay: {836 markRootSuspended(root, lanes);837 if (includesOnlyTransitions(lanes)) {838 // This is a transition, so we should exit without committing a839 // placeholder and without scheduling a timeout. Delay indefinitely840 // until we receive more data.841 break;842 }843 if (!shouldForceFlushFallbacksInDEV()) {844 // This is not a transition, but we did trigger an avoided state.845 // Schedule a placeholder to display after a short delay, using the Just846 // Noticeable Difference.847 // TODO: Is the JND optimization worth the added complexity? If this is848 // the only reason we track the event time, then probably not.849 // Consider removing.850 const mostRecentEventTime = getMostRecentEventTime(root, lanes);851 const eventTimeMs = mostRecentEventTime;852 const timeElapsedMs = now() - eventTimeMs;853 const msUntilTimeout = jnd(timeElapsedMs) - timeElapsedMs;854 // Don't bother with a very short suspense time.855 if (msUntilTimeout > 10) {856 // Instead of committing the fallback immediately, wait for more data857 // to arrive.858 root.timeoutHandle = scheduleTimeout(859 commitRoot.bind(null, root),860 msUntilTimeout,861 );862 break;863 }864 }865 // Commit the placeholder.866 commitRoot(root);867 break;868 }869 case RootCompleted: {870 // The work completed. Ready to commit.871 commitRoot(root);872 break;873 }874 default: {875 invariant(false, 'Unknown root exit status.');876 }877 }878}879function markRootSuspended(root, suspendedLanes) {880 // When suspending, we should always exclude lanes that were pinged or (more881 // rarely, since we try to avoid it) updated during the render phase.882 // TODO: Lol maybe there's a better way to factor this besides this883 // obnoxiously named function :)884 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootPingedLanes);885 suspendedLanes = removeLanes(suspendedLanes, workInProgressRootUpdatedLanes);886 markRootSuspended_dontCallThisOneDirectly(root, suspendedLanes);887}888// This is the entry point for synchronous tasks that don't go889// through Scheduler890function performSyncWorkOnRoot(root) {891 invariant(892 (executionContext & (RenderContext | CommitContext)) === NoContext,893 'Should not already be working.',894 );895 flushPassiveEffects();896 let lanes;897 let exitStatus;898 if (899 root === workInProgressRoot &&900 includesSomeLane(root.expiredLanes, workInProgressRootRenderLanes)901 ) {902 // There's a partial tree, and at least one of its lanes has expired. Finish903 // rendering it before rendering the rest of the expired work.904 lanes = workInProgressRootRenderLanes;905 exitStatus = renderRootSync(root, lanes);906 if (907 includesSomeLane(908 workInProgressRootIncludedLanes,909 workInProgressRootUpdatedLanes,910 )911 ) {912 // The render included lanes that were updated during the render phase.913 // For example, when unhiding a hidden tree, we include all the lanes914 // that were previously skipped when the tree was hidden. That set of915 // lanes is a superset of the lanes we started rendering with.916 //917 // Note that this only happens when part of the tree is rendered918 // concurrently. If the whole tree is rendered synchronously, then there919 // are no interleaved events.920 lanes = getNextLanes(root, lanes);921 exitStatus = renderRootSync(root, lanes);922 }923 } else {924 lanes = getNextLanes(root, NoLanes);925 exitStatus = renderRootSync(root, lanes);926 }927 if (root.tag !== LegacyRoot && exitStatus === RootErrored) {928 executionContext |= RetryAfterError;929 // If an error occurred during hydration,930 // discard server response and fall back to client side render.931 if (root.hydrate) {932 root.hydrate = false;933 clearContainer(root.containerInfo);934 }935 // If something threw an error, try rendering one more time. We'll render936 // synchronously to block concurrent data mutations, and we'll includes937 // all pending updates are included. If it still fails after the second938 // attempt, we'll give up and commit the resulting tree.939 lanes = getLanesToRetrySynchronouslyOnError(root);940 if (lanes !== NoLanes) {941 exitStatus = renderRootSync(root, lanes);942 }943 }944 if (exitStatus === RootFatalErrored) {945 const fatalError = workInProgressRootFatalError;946 prepareFreshStack(root, NoLanes);947 markRootSuspended(root, lanes);948 ensureRootIsScheduled(root, now());949 throw fatalError;950 }951 // We now have a consistent tree. Because this is a sync render, we952 // will commit it even if something suspended.953 const finishedWork: Fiber = (root.current.alternate: any);954 root.finishedWork = finishedWork;955 root.finishedLanes = lanes;956 commitRoot(root);957 // Before exiting, make sure there's a callback scheduled for the next958 // pending level.959 ensureRootIsScheduled(root, now());960 return null;961}962export function flushRoot(root: FiberRoot, lanes: Lanes) {963 markRootExpired(root, lanes);964 ensureRootIsScheduled(root, now());965 if ((executionContext & (RenderContext | CommitContext)) === NoContext) {966 resetRenderTimer();967 flushSyncCallbackQueue();968 }969}970export function getExecutionContext(): ExecutionContext {971 return executionContext;972}973export function flushDiscreteUpdates() {974 // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.975 // However, `act` uses `batchedUpdates`, so there's no way to distinguish976 // those two cases. Need to fix this before exposing flushDiscreteUpdates977 // as a public API.978 if (979 (executionContext & (BatchedContext | RenderContext | CommitContext)) !==980 NoContext981 ) {982 if (__DEV__) {983 if ((executionContext & RenderContext) !== NoContext) {984 console.error(985 'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +986 'already rendering.',987 );988 }989 }990 // We're already rendering, so we can't synchronously flush pending work.991 // This is probably a nested event dispatch triggered by a lifecycle/effect,992 // like `el.focus()`. Exit.993 return;994 }995 flushPendingDiscreteUpdates();996 // If the discrete updates scheduled passive effects, flush them now so that997 // they fire before the next serial event.998 flushPassiveEffects();999}1000export function deferredUpdates<A>(fn: () => A): A {1001 if (decoupleUpdatePriorityFromScheduler) {1002 const previousLanePriority = getCurrentUpdateLanePriority();1003 try {1004 setCurrentUpdateLanePriority(DefaultLanePriority);1005 return runWithPriority(NormalSchedulerPriority, fn);1006 } finally {1007 setCurrentUpdateLanePriority(previousLanePriority);1008 }1009 } else {1010 return runWithPriority(NormalSchedulerPriority, fn);1011 }1012}1013function flushPendingDiscreteUpdates() {1014 if (rootsWithPendingDiscreteUpdates !== null) {1015 // For each root with pending discrete updates, schedule a callback to1016 // immediately flush them.1017 const roots = rootsWithPendingDiscreteUpdates;1018 rootsWithPendingDiscreteUpdates = null;1019 roots.forEach(root => {1020 markDiscreteUpdatesExpired(root);1021 ensureRootIsScheduled(root, now());1022 });1023 }1024 // Now flush the immediate queue.1025 flushSyncCallbackQueue();1026}1027export function batchedUpdates<A, R>(fn: A => R, a: A): R {1028 const prevExecutionContext = executionContext;1029 executionContext |= BatchedContext;1030 try {1031 return fn(a);1032 } finally {1033 executionContext = prevExecutionContext;1034 if (executionContext === NoContext) {1035 // Flush the immediate callbacks that were scheduled during this batch1036 resetRenderTimer();1037 flushSyncCallbackQueue();1038 }1039 }1040}1041export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {1042 const prevExecutionContext = executionContext;1043 executionContext |= EventContext;1044 try {1045 return fn(a);1046 } finally {1047 executionContext = prevExecutionContext;1048 if (executionContext === NoContext) {1049 // Flush the immediate callbacks that were scheduled during this batch1050 resetRenderTimer();1051 flushSyncCallbackQueue();1052 }1053 }1054}1055export function discreteUpdates<A, B, C, D, R>(1056 fn: (A, B, C) => R,1057 a: A,1058 b: B,1059 c: C,1060 d: D,1061): R {1062 const prevExecutionContext = executionContext;1063 executionContext |= DiscreteEventContext;1064 if (decoupleUpdatePriorityFromScheduler) {1065 const previousLanePriority = getCurrentUpdateLanePriority();1066 try {1067 setCurrentUpdateLanePriority(InputDiscreteLanePriority);1068 return runWithPriority(1069 UserBlockingSchedulerPriority,1070 fn.bind(null, a, b, c, d),1071 );1072 } finally {1073 setCurrentUpdateLanePriority(previousLanePriority);1074 executionContext = prevExecutionContext;1075 if (executionContext === NoContext) {1076 // Flush the immediate callbacks that were scheduled during this batch1077 resetRenderTimer();1078 flushSyncCallbackQueue();1079 }1080 }1081 } else {1082 try {1083 return runWithPriority(1084 UserBlockingSchedulerPriority,1085 fn.bind(null, a, b, c, d),1086 );1087 } finally {1088 executionContext = prevExecutionContext;1089 if (executionContext === NoContext) {1090 // Flush the immediate callbacks that were scheduled during this batch1091 resetRenderTimer();1092 flushSyncCallbackQueue();1093 }1094 }1095 }1096}1097export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1098 const prevExecutionContext = executionContext;1099 executionContext &= ~BatchedContext;1100 executionContext |= LegacyUnbatchedContext;1101 try {1102 return fn(a);1103 } finally {1104 executionContext = prevExecutionContext;1105 if (executionContext === NoContext) {1106 // Flush the immediate callbacks that were scheduled during this batch1107 resetRenderTimer();1108 flushSyncCallbackQueue();1109 }1110 }1111}1112export function flushSync<A, R>(fn: A => R, a: A): R {1113 const prevExecutionContext = executionContext;1114 if ((prevExecutionContext & (RenderContext | CommitContext)) !== NoContext) {1115 if (__DEV__) {1116 console.error(1117 'flushSync was called from inside a lifecycle method. React cannot ' +1118 'flush when React is already rendering. Consider moving this call to ' +1119 'a scheduler task or micro task.',1120 );1121 }1122 return fn(a);1123 }1124 executionContext |= BatchedContext;1125 if (decoupleUpdatePriorityFromScheduler) {1126 const previousLanePriority = getCurrentUpdateLanePriority();1127 try {1128 setCurrentUpdateLanePriority(SyncLanePriority);1129 if (fn) {1130 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));1131 } else {1132 return (undefined: $FlowFixMe);1133 }1134 } finally {1135 setCurrentUpdateLanePriority(previousLanePriority);1136 executionContext = prevExecutionContext;1137 // Flush the immediate callbacks that were scheduled during this batch.1138 // Note that this will happen even if batchedUpdates is higher up1139 // the stack.1140 flushSyncCallbackQueue();1141 }1142 } else {1143 try {1144 if (fn) {1145 return runWithPriority(ImmediateSchedulerPriority, fn.bind(null, a));1146 } else {1147 return (undefined: $FlowFixMe);1148 }1149 } finally {1150 executionContext = prevExecutionContext;1151 // Flush the immediate callbacks that were scheduled during this batch.1152 // Note that this will happen even if batchedUpdates is higher up1153 // the stack.1154 flushSyncCallbackQueue();1155 }1156 }1157}1158export function flushControlled(fn: () => mixed): void {1159 const prevExecutionContext = executionContext;1160 executionContext |= BatchedContext;1161 if (decoupleUpdatePriorityFromScheduler) {1162 const previousLanePriority = getCurrentUpdateLanePriority();1163 try {1164 setCurrentUpdateLanePriority(SyncLanePriority);1165 runWithPriority(ImmediateSchedulerPriority, fn);1166 } finally {1167 setCurrentUpdateLanePriority(previousLanePriority);1168 executionContext = prevExecutionContext;1169 if (executionContext === NoContext) {1170 // Flush the immediate callbacks that were scheduled during this batch1171 resetRenderTimer();1172 flushSyncCallbackQueue();1173 }1174 }1175 } else {1176 try {1177 runWithPriority(ImmediateSchedulerPriority, fn);1178 } finally {1179 executionContext = prevExecutionContext;1180 if (executionContext === NoContext) {1181 // Flush the immediate callbacks that were scheduled during this batch1182 resetRenderTimer();1183 flushSyncCallbackQueue();1184 }1185 }1186 }1187}1188export function pushRenderLanes(fiber: Fiber, lanes: Lanes) {1189 pushToStack(subtreeRenderLanesCursor, subtreeRenderLanes, fiber);1190 subtreeRenderLanes = mergeLanes(subtreeRenderLanes, lanes);1191 workInProgressRootIncludedLanes = mergeLanes(1192 workInProgressRootIncludedLanes,1193 lanes,1194 );1195}1196export function popRenderLanes(fiber: Fiber) {1197 subtreeRenderLanes = subtreeRenderLanesCursor.current;1198 popFromStack(subtreeRenderLanesCursor, fiber);1199}1200function prepareFreshStack(root: FiberRoot, lanes: Lanes) {1201 root.finishedWork = null;1202 root.finishedLanes = NoLanes;1203 const timeoutHandle = root.timeoutHandle;1204 if (timeoutHandle !== noTimeout) {1205 // The root previous suspended and scheduled a timeout to commit a fallback1206 // state. Now that we have additional work, cancel the timeout.1207 root.timeoutHandle = noTimeout;1208 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1209 cancelTimeout(timeoutHandle);1210 }1211 if (workInProgress !== null) {1212 let interruptedWork = workInProgress.return;1213 while (interruptedWork !== null) {1214 unwindInterruptedWork(interruptedWork);1215 interruptedWork = interruptedWork.return;1216 }1217 }1218 workInProgressRoot = root;1219 workInProgress = createWorkInProgress(root.current, null);1220 workInProgressRootRenderLanes = subtreeRenderLanes = workInProgressRootIncludedLanes = lanes;1221 workInProgressRootExitStatus = RootIncomplete;1222 workInProgressRootFatalError = null;1223 workInProgressRootSkippedLanes = NoLanes;1224 workInProgressRootUpdatedLanes = NoLanes;1225 workInProgressRootPingedLanes = NoLanes;1226 if (enableSchedulerTracing) {1227 spawnedWorkDuringRender = null;1228 }1229 if (__DEV__) {1230 ReactStrictModeWarnings.discardPendingWarnings();1231 }1232}1233function handleError(root, thrownValue): void {1234 do {1235 let erroredWork = workInProgress;1236 try {1237 // Reset module-level state that was set during the render phase.1238 resetContextDependencies();1239 resetHooksAfterThrow();1240 resetCurrentDebugFiberInDEV();1241 // TODO: I found and added this missing line while investigating a1242 // separate issue. Write a regression test using string refs.1243 ReactCurrentOwner.current = null;1244 if (erroredWork === null || erroredWork.return === null) {1245 // Expected to be working on a non-root fiber. This is a fatal error1246 // because there's no ancestor that can handle it; the root is1247 // supposed to capture all errors that weren't caught by an error1248 // boundary.1249 workInProgressRootExitStatus = RootFatalErrored;1250 workInProgressRootFatalError = thrownValue;1251 // Set `workInProgress` to null. This represents advancing to the next1252 // sibling, or the parent if there are no siblings. But since the root1253 // has no siblings nor a parent, we set it to null. Usually this is1254 // handled by `completeUnitOfWork` or `unwindWork`, but since we're1255 // intentionally not calling those, we need set it here.1256 // TODO: Consider calling `unwindWork` to pop the contexts.1257 workInProgress = null;1258 return;1259 }1260 if (enableProfilerTimer && erroredWork.mode & ProfileMode) {1261 // Record the time spent rendering before an error was thrown. This1262 // avoids inaccurate Profiler durations in the case of a1263 // suspended render.1264 stopProfilerTimerIfRunningAndRecordDelta(erroredWork, true);1265 }1266 throwException(1267 root,1268 erroredWork.return,1269 erroredWork,1270 thrownValue,1271 workInProgressRootRenderLanes,1272 );1273 completeUnitOfWork(erroredWork);1274 } catch (yetAnotherThrownValue) {1275 // Something in the return path also threw.1276 thrownValue = yetAnotherThrownValue;1277 if (workInProgress === erroredWork && erroredWork !== null) {1278 // If this boundary has already errored, then we had trouble processing1279 // the error. Bubble it to the next boundary.1280 erroredWork = erroredWork.return;1281 workInProgress = erroredWork;1282 } else {1283 erroredWork = workInProgress;1284 }1285 continue;1286 }1287 // Return to the normal work loop.1288 return;1289 } while (true);1290}1291function pushDispatcher() {1292 const prevDispatcher = ReactCurrentDispatcher.current;1293 ReactCurrentDispatcher.current = ContextOnlyDispatcher;1294 if (prevDispatcher === null) {1295 // The React isomorphic package does not include a default dispatcher.1296 // Instead the first renderer will lazily attach one, in order to give1297 // nicer error messages.1298 return ContextOnlyDispatcher;1299 } else {1300 return prevDispatcher;1301 }1302}1303function popDispatcher(prevDispatcher) {1304 ReactCurrentDispatcher.current = prevDispatcher;1305}1306function pushInteractions(root) {1307 if (enableSchedulerTracing) {1308 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1309 __interactionsRef.current = root.memoizedInteractions;1310 return prevInteractions;1311 }1312 return null;1313}1314function popInteractions(prevInteractions) {1315 if (enableSchedulerTracing) {1316 __interactionsRef.current = prevInteractions;1317 }1318}1319export function markCommitTimeOfFallback() {1320 globalMostRecentFallbackTime = now();1321}1322export function markSkippedUpdateLanes(lane: Lane | Lanes): void {1323 workInProgressRootSkippedLanes = mergeLanes(1324 lane,1325 workInProgressRootSkippedLanes,1326 );1327}1328export function renderDidSuspend(): void {1329 if (workInProgressRootExitStatus === RootIncomplete) {1330 workInProgressRootExitStatus = RootSuspended;1331 }1332}1333export function renderDidSuspendDelayIfPossible(): void {1334 if (1335 workInProgressRootExitStatus === RootIncomplete ||1336 workInProgressRootExitStatus === RootSuspended1337 ) {1338 workInProgressRootExitStatus = RootSuspendedWithDelay;1339 }1340 // Check if there are updates that we skipped tree that might have unblocked1341 // this render.1342 if (1343 workInProgressRoot !== null &&1344 (includesNonIdleWork(workInProgressRootSkippedLanes) ||1345 includesNonIdleWork(workInProgressRootUpdatedLanes))1346 ) {1347 // Mark the current render as suspended so that we switch to working on1348 // the updates that were skipped. Usually we only suspend at the end of1349 // the render phase.1350 // TODO: We should probably always mark the root as suspended immediately1351 // (inside this function), since by suspending at the end of the render1352 // phase introduces a potential mistake where we suspend lanes that were1353 // pinged or updated while we were rendering.1354 markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes);1355 }1356}1357export function renderDidError() {1358 if (workInProgressRootExitStatus !== RootCompleted) {1359 workInProgressRootExitStatus = RootErrored;1360 }1361}1362// Called during render to determine if anything has suspended.1363// Returns false if we're not sure.1364export function renderHasNotSuspendedYet(): boolean {1365 // If something errored or completed, we can't really be sure,1366 // so those are false.1367 return workInProgressRootExitStatus === RootIncomplete;1368}1369function renderRootSync(root: FiberRoot, lanes: Lanes) {1370 const prevExecutionContext = executionContext;1371 executionContext |= RenderContext;1372 const prevDispatcher = pushDispatcher();1373 // If the root or lanes have changed, throw out the existing stack1374 // and prepare a fresh one. Otherwise we'll continue where we left off.1375 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1376 prepareFreshStack(root, lanes);1377 startWorkOnPendingInteractions(root, lanes);1378 }1379 const prevInteractions = pushInteractions(root);1380 if (__DEV__) {1381 if (enableDebugTracing) {1382 logRenderStarted(lanes);1383 }1384 }1385 if (enableSchedulingProfiler) {1386 markRenderStarted(lanes);1387 }1388 do {1389 try {1390 workLoopSync();1391 break;1392 } catch (thrownValue) {1393 handleError(root, thrownValue);1394 }1395 } while (true);1396 resetContextDependencies();1397 if (enableSchedulerTracing) {1398 popInteractions(((prevInteractions: any): Set<Interaction>));1399 }1400 executionContext = prevExecutionContext;1401 popDispatcher(prevDispatcher);1402 if (workInProgress !== null) {1403 // This is a sync render, so we should have finished the whole tree.1404 invariant(1405 false,1406 'Cannot commit an incomplete root. This error is likely caused by a ' +1407 'bug in React. Please file an issue.',1408 );1409 }1410 if (__DEV__) {1411 if (enableDebugTracing) {1412 logRenderStopped();1413 }1414 }1415 if (enableSchedulingProfiler) {1416 markRenderStopped();1417 }1418 // Set this to null to indicate there's no in-progress render.1419 workInProgressRoot = null;1420 workInProgressRootRenderLanes = NoLanes;1421 return workInProgressRootExitStatus;1422}1423// The work loop is an extremely hot path. Tell Closure not to inline it.1424/** @noinline */1425function workLoopSync() {1426 // Already timed out, so perform work without checking if we need to yield.1427 while (workInProgress !== null) {1428 performUnitOfWork(workInProgress);1429 }1430}1431function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {1432 const prevExecutionContext = executionContext;1433 executionContext |= RenderContext;1434 const prevDispatcher = pushDispatcher();1435 // If the root or lanes have changed, throw out the existing stack1436 // and prepare a fresh one. Otherwise we'll continue where we left off.1437 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1438 resetRenderTimer();1439 prepareFreshStack(root, lanes);1440 startWorkOnPendingInteractions(root, lanes);1441 }1442 const prevInteractions = pushInteractions(root);1443 if (__DEV__) {1444 if (enableDebugTracing) {1445 logRenderStarted(lanes);1446 }1447 }1448 if (enableSchedulingProfiler) {1449 markRenderStarted(lanes);1450 }1451 do {1452 try {...
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...62 // more and prefer CPU suspense heuristics instead.63 var workInProgressRootRenderTargetTime = Infinity; // How long a render is supposed to take before we start following CPU64 // suspense heuristics and opt out of rendering more content.65 var RENDER_TIMEOUT_MS = 500;66 function resetRenderTimer() {67 workInProgressRootRenderTargetTime = now() + RENDER_TIMEOUT_MS;68 }69 function getRenderTargetTime() {70 return workInProgressRootRenderTargetTime;71 }72 var nextEffect = null;73 var hasUncaughtError = false;74 var firstUncaughtError = null;75 var legacyErrorBoundariesThatAlreadyFailed = null;76 var rootDoesHavePassiveEffects = false;77 var rootWithPendingPassiveEffects = null;78 var pendingPassiveEffectsRenderPriority = NoPriority$1;79 var pendingPassiveEffectsLanes = NoLanes;80 var pendingPassiveHookEffectsMount = [];81 var pendingPassiveHookEffectsUnmount = [];82 var rootsWithPendingDiscreteUpdates = null; // Use these to prevent an infinite loop of nested updates83 var NESTED_UPDATE_LIMIT = 50;84 var nestedUpdateCount = 0;85 var rootWithNestedUpdates = null;86 var NESTED_PASSIVE_UPDATE_LIMIT = 50;87 var nestedPassiveUpdateCount = 0; // Marks the need to reschedule pending interactions at these lanes88 // during the commit phase. This enables them to be traced across components89 // that spawn new work during render. E.g. hidden boundaries, suspended SSR90 // hydration or SuspenseList.91 // TODO: Can use a bitmask instead of an array92 var spawnedWorkDuringRender = null; // If two updates are scheduled within the same event, we should treat their93 // event times as simultaneous, even if the actual clock time has advanced94 // between the first and second call.95 var currentEventTime = NoTimestamp;96 var currentEventWipLanes = NoLanes;97 var currentEventPendingLanes = NoLanes; // Dev only flag that tracks if passive effects are currently being flushed.98 // We warn about state updates for unmounted components differently in this case.99 var isFlushingPassiveEffects = false;100 var focusedInstanceHandle = null;101 var shouldFireAfterActiveInstanceBlur = false;102 function getWorkInProgressRoot() {103 return workInProgressRoot;104 }105 function requestEventTime() {106 if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {107 // We're inside React, so it's fine to read the actual time.108 return now();109 } // We're not inside React, so we may be in the middle of a browser event.110 if (currentEventTime !== NoTimestamp) {111 // Use the same start time for all updates until we enter React again.112 return currentEventTime;113 } // This is the first update since React yielded. Compute a new start time.114 currentEventTime = now();115 return currentEventTime;116 }117 function requestUpdateLane(fiber) {118 // Special cases119 var mode = fiber.mode;120 if ((mode & BlockingMode) === NoMode) {121 return SyncLane;122 } else if ((mode & ConcurrentMode) === NoMode) {123 return getCurrentPriorityLevel() === ImmediatePriority$1 ? SyncLane : SyncBatchedLane;124 } // The algorithm for assigning an update to a lane should be stable for all125 // updates at the same priority within the same event. To do this, the inputs126 // to the algorithm must be the same. For example, we use the `renderLanes`127 // to avoid choosing a lane that is already in the middle of rendering.128 //129 // However, the "included" lanes could be mutated in between updates in the130 // same event, like if you perform an update inside `flushSync`. Or any other131 // code path that might call `prepareFreshStack`.132 //133 // The trick we use is to cache the first of each of these inputs within an134 // event. Then reset the cached values once we can be sure the event is over.135 // Our heuristic for that is whenever we enter a concurrent work loop.136 //137 // We'll do the same for `currentEventPendingLanes` below.138 if (currentEventWipLanes === NoLanes) {139 currentEventWipLanes = workInProgressRootIncludedLanes;140 }141 var isTransition = requestCurrentTransition() !== NoTransition;142 if (isTransition) {143 if (currentEventPendingLanes !== NoLanes) {144 currentEventPendingLanes = mostRecentlyUpdatedRoot !== null ? mostRecentlyUpdatedRoot.pendingLanes : NoLanes;145 }146 return findTransitionLane(currentEventWipLanes, currentEventPendingLanes);147 } // TODO: Remove this dependency on the Scheduler priority.148 // To do that, we're replacing it with an update lane priority.149 var schedulerPriority = getCurrentPriorityLevel(); // The old behavior was using the priority level of the Scheduler.150 // This couples React to the Scheduler internals, so we're replacing it151 // with the currentUpdateLanePriority above. As an example of how this152 // could be problematic, if we're not inside `Scheduler.runWithPriority`,153 // then we'll get the priority of the current running Scheduler task,154 // which is probably not what we want.155 var lane;156 if ( // TODO: Temporary. We're removing the concept of discrete updates.157 (executionContext & DiscreteEventContext) !== NoContext && schedulerPriority === UserBlockingPriority$2) {158 lane = findUpdateLane(InputDiscreteLanePriority, currentEventWipLanes);159 } else {160 var schedulerLanePriority = schedulerPriorityToLanePriority(schedulerPriority);161 lane = findUpdateLane(schedulerLanePriority, currentEventWipLanes);162 }163 return lane;164 }165 function requestRetryLane(fiber) {166 // This is a fork of `requestUpdateLane` designed specifically for Suspense167 // "retries" â a special update that attempts to flip a Suspense boundary168 // from its placeholder state to its primary/resolved state.169 // Special cases170 var mode = fiber.mode;171 if ((mode & BlockingMode) === NoMode) {172 return SyncLane;173 } else if ((mode & ConcurrentMode) === NoMode) {174 return getCurrentPriorityLevel() === ImmediatePriority$1 ? SyncLane : SyncBatchedLane;175 } // See `requestUpdateLane` for explanation of `currentEventWipLanes`176 if (currentEventWipLanes === NoLanes) {177 currentEventWipLanes = workInProgressRootIncludedLanes;178 }179 return findRetryLane(currentEventWipLanes);180 }181 function scheduleUpdateOnFiber(fiber, lane, eventTime) {182 checkForNestedUpdates();183 warnAboutRenderPhaseUpdatesInDEV(fiber);184 var root = markUpdateLaneFromFiberToRoot(fiber, lane);185 if (root === null) {186 warnAboutUpdateOnUnmountedFiberInDEV(fiber);187 return null;188 } // Mark that the root has a pending update.189 markRootUpdated(root, lane, eventTime);190 if (root === workInProgressRoot) {191 // Received an update to a tree that's in the middle of rendering. Mark192 // that there was an interleaved update work on this root. Unless the193 // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render194 // phase update. In that case, we don't treat render phase updates as if195 // they were interleaved, for backwards compat reasons.196 {197 workInProgressRootUpdatedLanes = mergeLanes(workInProgressRootUpdatedLanes, lane);198 }199 if (workInProgressRootExitStatus === RootSuspendedWithDelay) {200 // The root already suspended with a delay, which means this render201 // definitely won't finish. Since we have a new update, let's mark it as202 // suspended now, right before marking the incoming update. This has the203 // effect of interrupting the current render and switching to the update.204 // TODO: Make sure this doesn't override pings that happen while we've205 // already started rendering.206 markRootSuspended$1(root, workInProgressRootRenderLanes);207 }208 } // TODO: requestUpdateLanePriority also reads the priority. Pass the209 // priority as an argument to that function and this one.210 var priorityLevel = getCurrentPriorityLevel();211 if (lane === SyncLane) {212 if ( // Check if we're inside unbatchedUpdates213 (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering214 (executionContext & (RenderContext | CommitContext)) === NoContext) {215 // Register pending interactions on the root to avoid losing traced interaction data.216 schedulePendingInteractions(root, lane); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed217 // root inside of batchedUpdates should be synchronous, but layout updates218 // should be deferred until the end of the batch.219 performSyncWorkOnRoot(root);220 } else {221 ensureRootIsScheduled(root, eventTime);222 schedulePendingInteractions(root, lane);223 if (executionContext === NoContext) {224 // Flush the synchronous work now, unless we're already working or inside225 // a batch. This is intentionally inside scheduleUpdateOnFiber instead of226 // scheduleCallbackForFiber to preserve the ability to schedule a callback227 // without immediately flushing it. We only do this for user-initiated228 // updates, to preserve historical behavior of legacy mode.229 resetRenderTimer();230 flushSyncCallbackQueue();231 }232 }233 } else {234 // Schedule a discrete update but only if it's not Sync.235 if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered236 // discrete, even inside a discrete event.237 priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority$1)) {238 // This is the result of a discrete event. Track the lowest priority239 // discrete update per root so we can flush them early, if needed.240 if (rootsWithPendingDiscreteUpdates === null) {241 rootsWithPendingDiscreteUpdates = new Set([root]);242 } else {243 rootsWithPendingDiscreteUpdates.add(root);244 }245 } // Schedule other updates after in case the callback is sync.246 ensureRootIsScheduled(root, eventTime);247 schedulePendingInteractions(root, lane);248 } // We use this when assigning a lane for a transition inside249 // `requestUpdateLane`. We assume it's the same as the root being updated,250 // since in the common case of a single root app it probably is. If it's not251 // the same root, then it's not a huge deal, we just might batch more stuff252 // together more than necessary.253 mostRecentlyUpdatedRoot = root;254 } // This is split into a separate function so we can mark a fiber with pending255 // work without treating it as a typical update that originates from an event;256 // e.g. retrying a Suspense boundary isn't an update, but it does schedule work257 // on a fiber.258 function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {259 // Update the source fiber's lanes260 sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);261 var alternate = sourceFiber.alternate;262 if (alternate !== null) {263 alternate.lanes = mergeLanes(alternate.lanes, lane);264 }265 {266 if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {267 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);268 }269 } // Walk the parent path to the root and update the child expiration time.270 var node = sourceFiber;271 var parent = sourceFiber.return;272 while (parent !== null) {273 parent.childLanes = mergeLanes(parent.childLanes, lane);274 alternate = parent.alternate;275 if (alternate !== null) {276 alternate.childLanes = mergeLanes(alternate.childLanes, lane);277 } else {278 {279 if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {280 warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);281 }282 }283 }284 node = parent;285 parent = parent.return;286 }287 if (node.tag === HostRoot) {288 var root = node.stateNode;289 return root;290 } else {291 return null;292 }293 } // Use this function to schedule a task for a root. There's only one task per294 // root; if a task was already scheduled, we'll check to make sure the priority295 // of the existing task is the same as the priority of the next level that the296 // root has work on. This function is called on every update, and right before297 // exiting a task.298 function ensureRootIsScheduled(root, currentTime) {299 var existingCallbackNode = root.callbackNode; // Check if any lanes are being starved by other work. If so, mark them as300 // expired so we know to work on those next.301 markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority.302 var nextLanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes); // This returns the priority level computed during the `getNextLanes` call.303 var newCallbackPriority = returnNextLanesPriority();304 if (nextLanes === NoLanes) {305 // Special case: There's nothing to work on.306 if (existingCallbackNode !== null) {307 cancelCallback(existingCallbackNode);308 root.callbackNode = null;309 root.callbackPriority = NoLanePriority;310 }311 return;312 } // Check if there's an existing task. We may be able to reuse it.313 if (existingCallbackNode !== null) {314 var existingCallbackPriority = root.callbackPriority;315 if (existingCallbackPriority === newCallbackPriority) {316 // The priority hasn't changed. We can reuse the existing task. Exit.317 return;318 } // The priority changed. Cancel the existing callback. We'll schedule a new319 // one below.320 cancelCallback(existingCallbackNode);321 } // Schedule a new callback.322 var newCallbackNode;323 if (newCallbackPriority === SyncLanePriority) {324 // Special case: Sync React callbacks are scheduled on a special325 // internal queue326 newCallbackNode = scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root));327 } else if (newCallbackPriority === SyncBatchedLanePriority) {328 newCallbackNode = scheduleCallback(ImmediatePriority$1, performSyncWorkOnRoot.bind(null, root));329 } else {330 var schedulerPriorityLevel = lanePriorityToSchedulerPriority(newCallbackPriority);331 newCallbackNode = scheduleCallback(schedulerPriorityLevel, performConcurrentWorkOnRoot.bind(null, root));332 }333 root.callbackPriority = newCallbackPriority;334 root.callbackNode = newCallbackNode;335 } // This is the entry point for every concurrent task, i.e. anything that336 // goes through Scheduler.337 function performConcurrentWorkOnRoot(root) {338 // Since we know we're in a React event, we can clear the current339 // event time. The next update will compute a new event time.340 currentEventTime = NoTimestamp;341 currentEventWipLanes = NoLanes;342 currentEventPendingLanes = NoLanes;343 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {344 {345 throw Error( "Should not already be working." );346 }347 } // Flush any pending passive effects before deciding which lanes to work on,348 // in case they schedule additional work.349 var originalCallbackNode = root.callbackNode;350 var didFlushPassiveEffects = flushPassiveEffects();351 if (didFlushPassiveEffects) {352 // Something in the passive effect phase may have canceled the current task.353 // Check if the task node for this root was changed.354 if (root.callbackNode !== originalCallbackNode) {355 // The current task was canceled. Exit. We don't need to call356 // `ensureRootIsScheduled` because the check above implies either that357 // there's a new task, or that there's no remaining work on this root.358 return null;359 }360 } // Determine the next expiration time to work on, using the fields stored361 // on the root.362 var lanes = getNextLanes(root, root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes);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 {948 try {949 workLoopConcurrent();950 break;951 } catch (thrownValue) {952 handleError(root, thrownValue);953 }...
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js
...32 } finally {33 executionContext = prevExecutionContext;34 // if (executionContext === NoContext) {35 // // Flush the immediate callbacks that were scheduled during this batch36 // resetRenderTimer();37 // flushSyncCallbackQueue();38 // }39 }40}41export function scheduleUpdateOnFiber(fiber, lane = SyncLane, eventTime) {42 // const root = markUpdateLaneFromFiberToRoot(fiber, lane);43 // markRootUpdated(root, lane, eventTime);44 if (lane === SyncLane) {45 if (46 // Check if we're inside unbatchedUpdates47 (executionContext & LegacyUnbatchedContext) !== NoContext &&48 // Check if we're not already rendering49 (executionContext & (RenderContext | CommitContext)) === NoContext50 ) {...
Untitled-1.jsx
Source:Untitled-1.jsx
...9 } finally {10 // ...11 if (executionContext === NoContext) {12 // Flush the immediate callbacks that were scheduled during this batch13 resetRenderTimer();14 flushSyncCallbackQueue();15 }16 }17}18function legacyRenderSubtreeIntoContainer(parentComponent, children, container, forceHydrate, callback) {19 //...20 let root = container._reactRootContainer;21 let fiberRoot;22 if (!root) {23 // Initial mountã24 // ... é¦æ¬¡æè½½ï¼å建rooFiber25 // Initial mount should not be batched.26 unbatchedUpdates(function () {27 updateContainer(children, fiberRoot, parentComponent, callback);...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForTimeout(10000);7 await page.evaluate(() => {8 window.resetRenderTimer();9 });10 await page.waitForTimeout(10000);11 await browser.close();12})();13const { chromium } = require('playwright');14(async () => {15 const browser = await chromium.launch({ headless: false });16 const context = await browser.newContext();17 const page = await context.newPage();18 await page.waitForTimeout(10000);19 await page.evaluate(() => {20 window.resetRenderTimer();21 });22 await page.waitForTimeout(10000);23 await browser.close();24})();25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch({ headless: false });28 const context = await browser.newContext();29 const page = await context.newPage();30 await page.waitForTimeout(10000);31 await page.evaluate(() => {32 window.resetRenderTimer();33 });34 await page.waitForTimeout(10000);35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch({ headless: false });
Using AI Code Generation
1const playwright = require("playwright");2(async () => {3 const browser = await playwright.webkit.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.resetRenderTimer();7 await page.screenshot({ path: 'google.png' });8 await browser.close();9})();10const playwright = require("playwright");11(async () => {12 const browser = await playwright.webkit.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 await page.resetRenderTimer();16 await page.screenshot({ path: 'google.png' });17 await page.reload();18 await page.resetRenderTimer();19 await page.screenshot({ path: 'google2.png' });20 await browser.close();21})();
Using AI Code Generation
1const { resetRenderTimer } = require('playwright/lib/server/chromium/crBrowser');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const page = await browser.newPage();6 resetRenderTimer();7 await page.click('text=Google apps');8 await page.waitForTimeout(10000);9 await browser.close();10})();
Using AI Code Generation
1const { resetRenderTimer } = require('playwright/lib/server/browserContext');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 resetRenderTimer(context);7 const page = await context.newPage();8 await page.screenshot({ path: 'google.png' });9 await browser.close();10})();
Using AI Code Generation
1const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');2resetRenderTimer();3const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');4resetRenderTimer();5const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');6resetRenderTimer();7const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');8resetRenderTimer();9const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');10resetRenderTimer();11const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');12resetRenderTimer();13const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');14resetRenderTimer();15const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');16resetRenderTimer();17const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');18resetRenderTimer();19const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');20resetRenderTimer();21const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');22resetRenderTimer();23const { resetRenderTimer } = require('playwright/lib/server/supplements/recorder/recorderApp');24resetRenderTimer();25const { resetRenderTimer } = require('playwright/lib/server/supplements/rec
Using AI Code Generation
1const { chromium } = require('playwright');2const { resetRenderTimer } = require('playwright/lib/internal/render');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const context = await browser.newContext();6 const page = await context.newPage();7 await resetRenderTimer(page);8 await browser.close();9})();10module.exports = { resetRenderTimer };11const { helper } = require('./helper');12const { assert } = require('../utils/utils');13const kRenderTimer = Symbol('RenderTimer');14const kRenderTimerTimeout = Symbol('RenderTimerTimeout');15const resetRenderTimer = async page => {16 assert(page, 'page', 'Page');17 await page.evaluate(() => {18 window[kRenderTimer] = 0;19 clearTimeout(window[kRenderTimerTimeout]);20 });21};22module.exports = { resetRenderTimer };23const { assert } = require('../utils/utils');24const helper = {25 getFromENV(name) {26 return process.env[name];27 },28};29module.exports = { helper };30const assert = (value, name, message) => {31 if (!value) throw new Error(`${name} ${message}`);32};33module.exports = { assert };34const assert = (value, name, message) => {35 if (!value) throw new Error(`${name} ${message}`);36};37module.exports = { assert };38const assert = (value, name, message) => {39 if (!value) throw new Error(`${name} ${message}`);40};41module.exports = { assert };42const assert = (value, name, message) => {43 if (!value) throw new Error(`${name} ${message}`);44};45module.exports = { assert };46const assert = (value, name, message) => {47 if (!value) throw new Error(`${name} ${message}`);48};49module.exports = { assert };50const assert = (value, name, message) => {51 if (!value) throw new Error(`${name} ${message}`);52};
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.
Get 100 minutes of automation test minutes FREE!!