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/recUsing 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!!
