Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js  
...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 {1453      workLoopConcurrent();1454      break;1455    } catch (thrownValue) {1456      handleError(root, thrownValue);1457    }1458  } while (true);1459  resetContextDependencies();1460  if (enableSchedulerTracing) {1461    popInteractions(((prevInteractions: any): Set<Interaction>));1462  }1463  popDispatcher(prevDispatcher);1464  executionContext = prevExecutionContext;1465  if (__DEV__) {1466    if (enableDebugTracing) {1467      logRenderStopped();1468    }1469  }1470  // Check if the tree has completed.1471  if (workInProgress !== null) {1472    // Still work remaining.1473    if (enableSchedulingProfiler) {1474      markRenderYielded();1475    }1476    return RootIncomplete;1477  } else {1478    // Completed the tree.1479    if (enableSchedulingProfiler) {1480      markRenderStopped();1481    }1482    // Set this to null to indicate there's no in-progress render.1483    workInProgressRoot = null;1484    workInProgressRootRenderLanes = NoLanes;1485    // Return the final exit status.1486    return workInProgressRootExitStatus;1487  }1488}1489/** @noinline */1490function workLoopConcurrent() {1491  // Perform work until Scheduler asks us to yield1492  while (workInProgress !== null && !shouldYield()) {1493    performUnitOfWork(workInProgress);1494  }1495}1496function performUnitOfWork(unitOfWork: Fiber): void {1497  // The current, flushed, state of this fiber is the alternate. Ideally1498  // nothing should rely on this, but relying on it here means that we don't1499  // need an additional field on the work in progress.1500  const current = unitOfWork.alternate;1501  setCurrentDebugFiberInDEV(unitOfWork);1502  let next;1503  if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {1504    startProfilerTimer(unitOfWork);1505    next = beginWork(current, unitOfWork, subtreeRenderLanes);1506    stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);1507  } else {1508    next = beginWork(current, unitOfWork, subtreeRenderLanes);1509  }1510  resetCurrentDebugFiberInDEV();1511  unitOfWork.memoizedProps = unitOfWork.pendingProps;1512  if (next === null) {1513    // If this doesn't spawn new work, complete the current work.1514    completeUnitOfWork(unitOfWork);1515  } else {1516    workInProgress = next;1517  }1518  ReactCurrentOwner.current = null;1519}1520function completeUnitOfWork(unitOfWork: Fiber): void {1521  // Attempt to complete the current unit of work, then move to the next1522  // sibling. If there are no more siblings, return to the parent fiber.1523  let completedWork = unitOfWork;1524  do {1525    // The current, flushed, state of this fiber is the alternate. Ideally1526    // nothing should rely on this, but relying on it here means that we don't1527    // need an additional field on the work in progress.1528    const current = completedWork.alternate;1529    const returnFiber = completedWork.return;1530    // Check if the work completed or if something threw.1531    if ((completedWork.flags & Incomplete) === NoFlags) {1532      setCurrentDebugFiberInDEV(completedWork);1533      let next;1534      if (1535        !enableProfilerTimer ||1536        (completedWork.mode & ProfileMode) === NoMode1537      ) {1538        next = completeWork(current, completedWork, subtreeRenderLanes);1539      } else {1540        startProfilerTimer(completedWork);1541        next = completeWork(current, completedWork, subtreeRenderLanes);1542        // Update render duration assuming we didn't error.1543        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1544      }1545      resetCurrentDebugFiberInDEV();1546      if (next !== null) {1547        // Completing this fiber spawned new work. Work on that next.1548        workInProgress = next;1549        return;1550      }1551    } else {1552      // This fiber did not complete because something threw. Pop values off1553      // the stack without entering the complete phase. If this is a boundary,1554      // capture values if possible.1555      const next = unwindWork(completedWork, subtreeRenderLanes);1556      // Because this fiber did not complete, don't reset its expiration time.1557      if (next !== null) {1558        // If completing this work spawned new work, do that next. We'll come1559        // back here again.1560        // Since we're restarting, remove anything that is not a host effect1561        // from the effect tag.1562        next.flags &= HostEffectMask;1563        workInProgress = next;1564        return;1565      }1566      if (1567        enableProfilerTimer &&1568        (completedWork.mode & ProfileMode) !== NoMode1569      ) {1570        // Record the render duration for the fiber that errored.1571        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1572        // Include the time spent working on failed children before continuing.1573        let actualDuration = completedWork.actualDuration;1574        let child = completedWork.child;1575        while (child !== null) {1576          actualDuration += child.actualDuration;1577          child = child.sibling;1578        }1579        completedWork.actualDuration = actualDuration;1580      }1581      if (returnFiber !== null) {1582        // Mark the parent fiber as incomplete1583        returnFiber.flags |= Incomplete;1584        returnFiber.subtreeFlags = NoFlags;1585        returnFiber.deletions = null;1586      }1587    }1588    const siblingFiber = completedWork.sibling;1589    if (siblingFiber !== null) {1590      // If there is more work to do in this returnFiber, do that next.1591      workInProgress = siblingFiber;1592      return;1593    }1594    // Otherwise, return to the parent1595    completedWork = returnFiber;1596    // Update the next thing we're working on in case something throws.1597    workInProgress = completedWork;1598  } while (completedWork !== null);1599  // We've reached the root.1600  if (workInProgressRootExitStatus === RootIncomplete) {1601    workInProgressRootExitStatus = RootCompleted;1602  }1603}1604function commitRoot(root) {1605  const renderPriorityLevel = getCurrentPriorityLevel();1606  runWithPriority(1607    ImmediateSchedulerPriority,1608    commitRootImpl.bind(null, root, renderPriorityLevel),1609  );1610  return null;1611}1612function commitRootImpl(root, renderPriorityLevel) {1613  do {1614    // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1615    // means `flushPassiveEffects` will sometimes result in additional1616    // passive effects. So we need to keep flushing in a loop until there are1617    // no more pending effects.1618    // TODO: Might be better if `flushPassiveEffects` did not automatically1619    // flush synchronous work at the end, to avoid factoring hazards like this.1620    flushPassiveEffects();1621  } while (rootWithPendingPassiveEffects !== null);1622  flushRenderPhaseStrictModeWarningsInDEV();1623  invariant(1624    (executionContext & (RenderContext | CommitContext)) === NoContext,1625    'Should not already be working.',1626  );1627  const finishedWork = root.finishedWork;1628  const lanes = root.finishedLanes;1629  if (__DEV__) {1630    if (enableDebugTracing) {1631      logCommitStarted(lanes);1632    }1633  }1634  if (enableSchedulingProfiler) {1635    markCommitStarted(lanes);1636  }1637  // 没æéè¦æ´æ°çFiberèç¹1638  if (finishedWork === null) {1639    if (__DEV__) {1640      if (enableDebugTracing) {1641        logCommitStopped();1642      }1643    }1644    if (enableSchedulingProfiler) {1645      markCommitStopped();1646    }1647    return null;1648  }1649  root.finishedWork = null;1650  root.finishedLanes = NoLanes;1651  invariant(1652    finishedWork !== root.current,1653    'Cannot commit the same tree as before. This error is likely caused by ' +1654      'a bug in React. Please file an issue.',1655  );1656  // commitRoot never returns a continuation; it always finishes synchronously.1657  // So we can clear these now to allow a new callback to be scheduled.1658  root.callbackNode = null;1659  // Update the first and last pending times on this root. The new first1660  // pending time is whatever is left on the root fiber.1661  // åå¹¶ææçéé1662  let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1663  markRootFinished(root, remainingLanes);1664  // Clear already finished discrete updates in case that a later call of1665  // `flushDiscreteUpdates` starts a useless render pass which may cancels1666  // a scheduled timeout.1667  if (rootsWithPendingDiscreteUpdates !== null) {1668    if (1669      !hasDiscreteLanes(remainingLanes) &&1670      rootsWithPendingDiscreteUpdates.has(root)1671    ) {1672      rootsWithPendingDiscreteUpdates.delete(root);1673    }1674  }1675  // è¯´ææ¬æ¬¡æ´æ°å·²ç»å®æäºï¼å°ä¸äºåééç½®1676  if (root === workInProgressRoot) {1677    // We can reset these now that they are finished.1678    workInProgressRoot = null;1679    workInProgress = null;1680    workInProgressRootRenderLanes = NoLanes;1681  } else {1682    // This indicates that the last root we worked on is not the same one that1683    // we're committing now. This most commonly happens when a suspended root1684    // times out.1685  }1686  // Check if there are any effects in the whole tree.1687  // TODO: This is left over from the effect list implementation, where we had1688  // to check for the existence of `firstEffect` to satsify Flow. I think the1689  // only other reason this optimization exists is because it affects profiling.1690  // Reconsider whether this is necessary.1691  const subtreeHasEffects =1692    (finishedWork.subtreeFlags &1693      (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1694    NoFlags;1695  const rootHasEffect =1696    (finishedWork.flags &1697      (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1698    NoFlags;1699    // æéè¦å¤ççå¯ä½ç¨1700  if (subtreeHasEffects || rootHasEffect) {1701    let previousLanePriority;1702    if (decoupleUpdatePriorityFromScheduler) {1703      previousLanePriority = getCurrentUpdateLanePriority();1704      setCurrentUpdateLanePriority(SyncLanePriority);1705    }1706    // 设置æ§è¡ä¸ä¸æ1707    const prevExecutionContext = executionContext;1708    executionContext |= CommitContext;1709    const prevInteractions = pushInteractions(root);1710    // Reset this to null before calling lifecycles1711    ReactCurrentOwner.current = null;1712    // The commit phase is broken into several sub-phases. We do a separate pass1713    // of the effect list for each phase: all mutation effects come before all1714    // layout effects, and so on.1715    // The first phase a "before mutation" phase. We use this phase to read the1716    // state of the host tree right before we mutate it. This is where1717    // getSnapshotBeforeUpdate is called.1718    focusedInstanceHandle = prepareForCommit(root.containerInfo);1719    shouldFireAfterActiveInstanceBlur = false;1720    commitBeforeMutationEffects(finishedWork);1721    // We no longer need to track the active instance fiber1722    focusedInstanceHandle = null;1723    if (enableProfilerTimer) {1724      // Mark the current commit time to be shared by all Profilers in this1725      // batch. This enables them to be grouped later.1726      recordCommitTime();1727    }1728    // æDOMå
素渲æå°é¡µé¢ä¸1729    // The next phase is the mutation phase, where we mutate the host tree.1730    commitMutationEffects(finishedWork, root, renderPriorityLevel);1731    if (shouldFireAfterActiveInstanceBlur) {1732      afterActiveInstanceBlur();1733    }1734    resetAfterCommit(root.containerInfo);1735    // The work-in-progress tree is now the current tree. This must come after1736    // the mutation phase, so that the previous tree is still current during1737    // componentWillUnmount, but before the layout phase, so that the finished1738    // work is current during componentDidMount/Update.1739    // 卿¤ä¹åï¼root.current æåäºwork-in-progress tree1740    root.current = finishedWork;1741    // The next phase is the layout phase, where we call effects that read1742    // the host tree after it's been mutated. The idiomatic use case for this is1743    // layout, but class component lifecycles also fire here for legacy reasons.1744    if (__DEV__) {1745      if (enableDebugTracing) {1746        logLayoutEffectsStarted(lanes);1747      }1748    }1749    if (enableSchedulingProfiler) {1750      markLayoutEffectsStarted(lanes);1751    }1752    if (__DEV__) {1753      setCurrentDebugFiberInDEV(finishedWork);1754      invokeGuardedCallback(1755        null,1756        recursivelyCommitLayoutEffects,1757        null,1758        finishedWork,1759        root,1760      );1761      if (hasCaughtError()) {1762        const error = clearCaughtError();1763        captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1764      }1765      resetCurrentDebugFiberInDEV();1766    } else {1767      try {1768        recursivelyCommitLayoutEffects(finishedWork, root);1769      } catch (error) {1770        captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1771      }1772    }1773    if (__DEV__) {1774      if (enableDebugTracing) {1775        logLayoutEffectsStopped();1776      }1777    }1778    if (enableSchedulingProfiler) {1779      markLayoutEffectsStopped();1780    }1781    // If there are pending passive effects, schedule a callback to process them.1782    if (1783      (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||1784      (finishedWork.flags & PassiveMask) !== NoFlags1785    ) {1786      if (!rootDoesHavePassiveEffects) {1787        rootDoesHavePassiveEffects = true;1788        scheduleCallback(NormalSchedulerPriority, () => {1789          flushPassiveEffects();1790          return null;1791        });1792      }1793    }1794    // Tell Scheduler to yield at the end of the frame, so the browser has an1795    // opportunity to paint.1796    requestPaint();1797    if (enableSchedulerTracing) {1798      popInteractions(((prevInteractions: any): Set<Interaction>));1799    }1800    executionContext = prevExecutionContext;1801    if (decoupleUpdatePriorityFromScheduler && previousLanePriority != null) {1802      // Reset the priority to the previous non-sync value.1803      setCurrentUpdateLanePriority(previousLanePriority);1804    }1805  } else {1806    // No effects.1807    root.current = finishedWork;1808    // Measure these anyway so the flamegraph explicitly shows that there were1809    // no effects.1810    // TODO: Maybe there's a better way to report this.1811    if (enableProfilerTimer) {1812      recordCommitTime();1813    }1814  }1815  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1816  if (rootDoesHavePassiveEffects) {1817    // This commit has passive effects. Stash a reference to them. But don't1818    // schedule a callback until after flushing layout work.1819    rootDoesHavePassiveEffects = false;1820    rootWithPendingPassiveEffects = root;1821    pendingPassiveEffectsLanes = lanes;1822    pendingPassiveEffectsRenderPriority = renderPriorityLevel;1823  }1824  // Read this again, since an effect might have updated it1825  remainingLanes = root.pendingLanes;1826  // Check if there's remaining work on this root1827  if (remainingLanes !== NoLanes) {1828    if (enableSchedulerTracing) {1829      if (spawnedWorkDuringRender !== null) {1830        const expirationTimes = spawnedWorkDuringRender;1831        spawnedWorkDuringRender = null;1832        for (let i = 0; i < expirationTimes.length; i++) {1833          scheduleInteractions(1834            root,1835            expirationTimes[i],1836            root.memoizedInteractions,1837          );1838        }1839      }1840      schedulePendingInteractions(root, remainingLanes);1841    }1842  } else {1843    // If there's no remaining work, we can clear the set of already failed1844    // error boundaries.1845    legacyErrorBoundariesThatAlreadyFailed = null;1846  }1847  if (__DEV__ && enableDoubleInvokingEffects) {1848    if (!rootDidHavePassiveEffects) {1849      commitDoubleInvokeEffectsInDEV(root.current, false);1850    }1851  }1852  if (enableSchedulerTracing) {1853    if (!rootDidHavePassiveEffects) {1854      // If there are no passive effects, then we can complete the pending interactions.1855      // Otherwise, we'll wait until after the passive effects are flushed.1856      // Wait to do this until after remaining work has been scheduled,1857      // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1858      finishPendingInteractions(root, lanes);1859    }1860  }1861  if (remainingLanes === SyncLane) {1862    // Count the number of times the root synchronously re-renders without1863    // finishing. If there are too many, it indicates an infinite update loop.1864    if (root === rootWithNestedUpdates) {1865      nestedUpdateCount++;1866    } else {1867      nestedUpdateCount = 0;1868      rootWithNestedUpdates = root;1869    }1870  } else {1871    nestedUpdateCount = 0;1872  }1873  onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);1874  if (__DEV__) {1875    onCommitRootTestSelector();1876  }1877  // Always call this before exiting `commitRoot`, to ensure that any1878  // additional work on this root is scheduled.1879  ensureRootIsScheduled(root, now());1880  if (hasUncaughtError) {1881    hasUncaughtError = false;1882    const error = firstUncaughtError;1883    firstUncaughtError = null;1884    throw error;1885  }1886  if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1887    if (__DEV__) {1888      if (enableDebugTracing) {1889        logCommitStopped();1890      }1891    }1892    if (enableSchedulingProfiler) {1893      markCommitStopped();1894    }1895    // This is a legacy edge case. We just committed the initial mount of1896    // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1897    // synchronously, but layout updates should be deferred until the end1898    // of the batch.1899    return null;1900  }1901  // If layout work was scheduled, flush it now.1902  flushSyncCallbackQueue();1903  if (__DEV__) {1904    if (enableDebugTracing) {1905      logCommitStopped();1906    }1907  }1908  if (enableSchedulingProfiler) {1909    markCommitStopped();1910  }1911  return null;1912}1913function commitBeforeMutationEffects(firstChild: Fiber) {1914  let fiber = firstChild;1915  while (fiber !== null) {1916    // å¤çéè¦å é¤çfiber autoFocusãblur é»è¾ã1917    if (fiber.deletions !== null) {1918      commitBeforeMutationEffectsDeletions(fiber.deletions);1919    }1920    // éå½è°ç¨å¤çåèç¹1921    if (fiber.child !== null) {1922      const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;1923      if (primarySubtreeFlags !== NoFlags) {1924        commitBeforeMutationEffects(fiber.child);1925      }1926    }1927    if (__DEV__) {1928      setCurrentDebugFiberInDEV(fiber);1929      invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);1930      if (hasCaughtError()) {1931        const error = clearCaughtError();1932        captureCommitPhaseError(fiber, fiber.return, error);1933      }1934      resetCurrentDebugFiberInDEV();1935    } else {1936      try {1937        // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1938        // 弿¥è°åº¦useEffect1939        commitBeforeMutationEffectsImpl(fiber);1940      } catch (error) {1941        captureCommitPhaseError(fiber, fiber.return, error);1942      }1943    }1944    // è¿åå
å¼èç¹ï¼æ¥ç循ç¯1945    fiber = fiber.sibling;1946  }1947}1948function commitBeforeMutationEffectsImpl(fiber: Fiber) {1949  const current = fiber.alternate;1950  const flags = fiber.flags;1951  if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1952    // Check to see if the focused element was inside of a hidden (Suspense) subtree.1953    // TODO: Move this out of the hot path using a dedicated effect tag.1954    if (1955      fiber.tag === SuspenseComponent &&1956      isSuspenseBoundaryBeingHidden(current, fiber) &&1957      doesFiberContain(fiber, focusedInstanceHandle)1958    ) {1959      shouldFireAfterActiveInstanceBlur = true;1960      beforeActiveInstanceBlur();1961    }1962  }1963  if ((flags & Snapshot) !== NoFlags) {1964    setCurrentDebugFiberInDEV(fiber);1965    // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1966    commitBeforeMutationEffectOnFiber(current, fiber);1967    resetCurrentDebugFiberInDEV();1968  }1969  // è°åº¦useEffect1970  if ((flags & Passive) !== NoFlags) {1971    // If there are passive effects, schedule a callback to flush at1972    // the earliest opportunity.1973    if (!rootDoesHavePassiveEffects) {1974      rootDoesHavePassiveEffects = true;1975      scheduleCallback(NormalSchedulerPriority, () => {1976        flushPassiveEffects();1977        return null;1978      });1979    }1980  }1981}1982function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {1983  for (let i = 0; i < deletions.length; i++) {1984    const fiber = deletions[i];1985    // TODO (effects) It would be nice to avoid calling doesFiberContain()1986    // Maybe we can repurpose one of the subtreeFlags positions for this instead?1987    // Use it to store which part of the tree the focused instance is in?1988    // This assumes we can safely determine that instance during the "render" phase.1989    if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {1990      shouldFireAfterActiveInstanceBlur = true;1991      beforeActiveInstanceBlur();1992    }1993  }1994}1995function commitMutationEffects(1996  firstChild: Fiber,1997  root: FiberRoot,1998  renderPriorityLevel: ReactPriorityLevel,1999) {2000  let fiber = firstChild;2001  while (fiber !== null) {2002    const deletions = fiber.deletions;2003    if (deletions !== null) {2004      commitMutationEffectsDeletions(2005        deletions,2006        fiber,2007        root,2008        renderPriorityLevel,2009      );2010    }2011    if (fiber.child !== null) {2012      const mutationFlags = fiber.subtreeFlags & MutationMask;2013      if (mutationFlags !== NoFlags) {2014        commitMutationEffects(fiber.child, root, renderPriorityLevel);2015      }2016    }2017    if (__DEV__) {2018      setCurrentDebugFiberInDEV(fiber);2019      invokeGuardedCallback(2020        null,2021        commitMutationEffectsImpl,2022        null,2023        fiber,2024        root,2025        renderPriorityLevel,2026      );2027      if (hasCaughtError()) {2028        const error = clearCaughtError();2029        captureCommitPhaseError(fiber, fiber.return, error);2030      }2031      resetCurrentDebugFiberInDEV();2032    } else {2033      try {2034        commitMutationEffectsImpl(fiber, root, renderPriorityLevel);2035      } catch (error) {2036        captureCommitPhaseError(fiber, fiber.return, error);2037      }2038    }2039    fiber = fiber.sibling;2040  }2041}2042function commitMutationEffectsImpl(2043  fiber: Fiber,2044  root: FiberRoot,2045  renderPriorityLevel,2046) {2047  const flags = fiber.flags;2048  if (flags & ContentReset) {2049    commitResetTextContent(fiber);2050  }2051  if (flags & Ref) {2052    const current = fiber.alternate;2053    if (current !== null) {2054      commitDetachRef(current);2055    }2056    if (enableScopeAPI) {2057      // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.2058      if (fiber.tag === ScopeComponent) {2059        commitAttachRef(fiber);2060      }2061    }2062  }2063  // The following switch statement is only concerned about placement,2064  // updates, and deletions. To avoid needing to add a case for every possible2065  // bitmap value, we remove the secondary effects from the effect tag and2066  // switch on that value.2067  const primaryFlags = flags & (Placement | Update | Hydrating);2068  switch (primaryFlags) {2069    case Placement: {2070      commitPlacement(fiber);2071      // Clear the "placement" from effect tag so that we know that this is2072      // inserted, before any life-cycles like componentDidMount gets called.2073      // TODO: findDOMNode doesn't rely on this any more but isMounted does2074      // and isMounted is deprecated anyway so we should be able to kill this.2075      fiber.flags &= ~Placement;2076      break;2077    }2078    case PlacementAndUpdate: {2079      // Placement2080      commitPlacement(fiber);2081      // Clear the "placement" from effect tag so that we know that this is2082      // inserted, before any life-cycles like componentDidMount gets called.2083      fiber.flags &= ~Placement;2084      // Update2085      const current = fiber.alternate;2086      commitWork(current, fiber);2087      break;2088    }2089    case Hydrating: {2090      fiber.flags &= ~Hydrating;2091      break;2092    }2093    case HydratingAndUpdate: {2094      fiber.flags &= ~Hydrating;2095      // Update2096      const current = fiber.alternate;2097      commitWork(current, fiber);2098      break;2099    }2100    case Update: {2101      const current = fiber.alternate;2102      commitWork(current, fiber);2103      break;2104    }2105  }2106}2107function commitMutationEffectsDeletions(2108  deletions: Array<Fiber>,2109  nearestMountedAncestor: Fiber,2110  root: FiberRoot,2111  renderPriorityLevel,2112) {2113  for (let i = 0; i < deletions.length; i++) {2114    const childToDelete = deletions[i];2115    if (__DEV__) {2116      invokeGuardedCallback(2117        null,2118        commitDeletion,2119        null,2120        root,2121        childToDelete,2122        nearestMountedAncestor,2123        renderPriorityLevel,2124      );2125      if (hasCaughtError()) {2126        const error = clearCaughtError();2127        captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2128      }2129    } else {2130      try {2131        commitDeletion(2132          root,2133          childToDelete,2134          nearestMountedAncestor,2135          renderPriorityLevel,2136        );2137      } catch (error) {2138        captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2139      }2140    }2141  }2142}2143export function schedulePassiveEffectCallback() {2144  if (!rootDoesHavePassiveEffects) {2145    rootDoesHavePassiveEffects = true;2146    scheduleCallback(NormalSchedulerPriority, () => {2147      flushPassiveEffects();2148      return null;2149    });2150  }2151}2152export function flushPassiveEffects(): boolean {2153  // Returns whether passive effects were flushed.2154  if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {2155    const priorityLevel =2156      pendingPassiveEffectsRenderPriority > NormalSchedulerPriority2157        ? NormalSchedulerPriority2158        : pendingPassiveEffectsRenderPriority;2159    pendingPassiveEffectsRenderPriority = NoSchedulerPriority;2160    if (decoupleUpdatePriorityFromScheduler) {2161      const previousLanePriority = getCurrentUpdateLanePriority();2162      try {2163        setCurrentUpdateLanePriority(2164          schedulerPriorityToLanePriority(priorityLevel),2165        );2166        return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2167      } finally {2168        setCurrentUpdateLanePriority(previousLanePriority);2169      }2170    } else {2171      return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2172    }2173  }2174  return false;2175}2176function flushPassiveMountEffects(root, firstChild: Fiber): void {2177  let fiber = firstChild;2178  while (fiber !== null) {2179    let prevProfilerOnStack = null;2180    if (enableProfilerTimer && enableProfilerCommitHooks) {2181      if (fiber.tag === Profiler) {2182        prevProfilerOnStack = nearestProfilerOnStack;2183        nearestProfilerOnStack = fiber;2184      }2185    }2186    const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;2187    if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {2188      flushPassiveMountEffects(root, fiber.child);2189    }2190    if ((fiber.flags & Passive) !== NoFlags) {2191      if (__DEV__) {2192        setCurrentDebugFiberInDEV(fiber);2193        invokeGuardedCallback(2194          null,2195          commitPassiveMountOnFiber,2196          null,2197          root,2198          fiber,2199        );2200        if (hasCaughtError()) {2201          const error = clearCaughtError();2202          captureCommitPhaseError(fiber, fiber.return, error);2203        }2204        resetCurrentDebugFiberInDEV();2205      } else {2206        try {2207          commitPassiveMountOnFiber(root, fiber);2208        } catch (error) {2209          captureCommitPhaseError(fiber, fiber.return, error);2210        }2211      }2212    }2213    if (enableProfilerTimer && enableProfilerCommitHooks) {2214      if (fiber.tag === Profiler) {2215        // Bubble times to the next nearest ancestor Profiler.2216        // After we process that Profiler, we'll bubble further up.2217        if (prevProfilerOnStack !== null) {2218          prevProfilerOnStack.stateNode.passiveEffectDuration +=2219            fiber.stateNode.passiveEffectDuration;2220        }2221        nearestProfilerOnStack = prevProfilerOnStack;2222      }2223    }2224    fiber = fiber.sibling;2225  }2226}2227function flushPassiveUnmountEffects(firstChild: Fiber): void {2228  let fiber = firstChild;2229  while (fiber !== null) {2230    const deletions = fiber.deletions;2231    if (deletions !== null) {2232      for (let i = 0; i < deletions.length; i++) {2233        const fiberToDelete = deletions[i];2234        flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber);2235        // Now that passive effects have been processed, it's safe to detach lingering pointers.2236        detachFiberAfterEffects(fiberToDelete);2237      }2238    }2239    const child = fiber.child;2240    if (child !== null) {2241      // If any children have passive effects then traverse the subtree.2242      // Note that this requires checking subtreeFlags of the current Fiber,2243      // rather than the subtreeFlags/effectsTag of the first child,2244      // since that would not cover passive effects in siblings.2245      const passiveFlags = fiber.subtreeFlags & PassiveMask;2246      if (passiveFlags !== NoFlags) {2247        flushPassiveUnmountEffects(child);2248      }2249    }2250    const primaryFlags = fiber.flags & Passive;2251    if (primaryFlags !== NoFlags) {2252      setCurrentDebugFiberInDEV(fiber);2253      commitPassiveUnmountOnFiber(fiber);2254      resetCurrentDebugFiberInDEV();2255    }2256    fiber = fiber.sibling;2257  }2258}2259function flushPassiveUnmountEffectsInsideOfDeletedTree(2260  fiberToDelete: Fiber,2261  nearestMountedAncestor: Fiber,2262): void {2263  if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {2264    // If any children have passive effects then traverse the subtree.2265    // Note that this requires checking subtreeFlags of the current Fiber,2266    // rather than the subtreeFlags/effectsTag of the first child,2267    // since that would not cover passive effects in siblings.2268    let child = fiberToDelete.child;2269    while (child !== null) {2270      flushPassiveUnmountEffectsInsideOfDeletedTree(2271        child,2272        nearestMountedAncestor,2273      );2274      child = child.sibling;2275    }2276  }2277  if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {2278    setCurrentDebugFiberInDEV(fiberToDelete);2279    commitPassiveUnmountInsideDeletedTreeOnFiber(2280      fiberToDelete,2281      nearestMountedAncestor,2282    );2283    resetCurrentDebugFiberInDEV();2284  }2285}2286function flushPassiveEffectsImpl() {2287  if (rootWithPendingPassiveEffects === null) {2288    return false;2289  }2290  const root = rootWithPendingPassiveEffects;2291  const lanes = pendingPassiveEffectsLanes;2292  rootWithPendingPassiveEffects = null;2293  pendingPassiveEffectsLanes = NoLanes;2294  invariant(2295    (executionContext & (RenderContext | CommitContext)) === NoContext,2296    'Cannot flush passive effects while already rendering.',2297  );2298  if (__DEV__) {2299    if (enableDebugTracing) {2300      logPassiveEffectsStarted(lanes);2301    }2302  }2303  if (enableSchedulingProfiler) {2304    markPassiveEffectsStarted(lanes);2305  }2306  if (__DEV__) {2307    isFlushingPassiveEffects = true;2308  }2309  const prevExecutionContext = executionContext;2310  executionContext |= CommitContext;2311  const prevInteractions = pushInteractions(root);2312  // It's important that ALL pending passive effect destroy functions are called2313  // before ANY passive effect create functions are called.2314  // Otherwise effects in sibling components might interfere with each other.2315  // e.g. a destroy function in one component may unintentionally override a ref2316  // value set by a create function in another component.2317  // Layout effects have the same constraint.2318  flushPassiveUnmountEffects(root.current);2319  flushPassiveMountEffects(root, root.current);2320  if (__DEV__) {2321    if (enableDebugTracing) {2322      logPassiveEffectsStopped();2323    }2324  }2325  if (enableSchedulingProfiler) {2326    markPassiveEffectsStopped();2327  }2328  if (__DEV__ && enableDoubleInvokingEffects) {2329    commitDoubleInvokeEffectsInDEV(root.current, true);2330  }2331  if (__DEV__) {2332    isFlushingPassiveEffects = false;2333  }2334  if (enableSchedulerTracing) {2335    popInteractions(((prevInteractions: any): Set<Interaction>));2336    finishPendingInteractions(root, lanes);2337  }2338  executionContext = prevExecutionContext;2339  flushSyncCallbackQueue();2340  // If additional passive effects were scheduled, increment a counter. If this2341  // exceeds the limit, we'll fire a warning.2342  nestedPassiveUpdateCount =2343    rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2344  return true;2345}2346export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2347  return (2348    legacyErrorBoundariesThatAlreadyFailed !== null &&2349    legacyErrorBoundariesThatAlreadyFailed.has(instance)...ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js  
...639      resetContextDependencies();640      executionContext = prevExecutionContext;641      popDispatcher(prevDispatcher);642      if (enableSchedulerTracing) {643        popInteractions(((prevInteractions: any): Set<Interaction>));644      }645      if (workInProgressRootExitStatus === RootFatalErrored) {646        const fatalError = workInProgressRootFatalError;647        stopInterruptedWorkLoopTimer();648        prepareFreshStack(root, expirationTime);649        markRootSuspendedAtTime(root, expirationTime);650        ensureRootIsScheduled(root);651        throw fatalError;652      }653      if (workInProgress !== null) {654        // There's still work left over. Exit without committing.655        stopInterruptedWorkLoopTimer();656      } else {657        // We now have a consistent tree. The next step is either to commit it,658        // or, if something suspended, wait to commit it after a timeout.659        stopFinishedWorkLoopTimer();660        const finishedWork: Fiber = ((root.finishedWork =661          root.current.alternate): any);662        root.finishedExpirationTime = expirationTime;663        finishConcurrentRender(664          root,665          finishedWork,666          workInProgressRootExitStatus,667          expirationTime,668        );669      }670      ensureRootIsScheduled(root);671      if (root.callbackNode === originalCallbackNode) {672        // The task node scheduled for this root is the same one that's673        // currently executed. Need to return a continuation.674        return performConcurrentWorkOnRoot.bind(null, root);675      }676    }677  }678  return null;679}680function finishConcurrentRender(681  root,682  finishedWork,683  exitStatus,684  expirationTime,685) {686  // Set this to null to indicate there's no in-progress render.687  workInProgressRoot = null;688  switch (exitStatus) {689    case RootIncomplete:690    case RootFatalErrored: {691      invariant(false, 'Root did not complete. This is a bug in React.');692    }693    // Flow knows about invariant, so it complains if I add a break694    // statement, but eslint doesn't know about invariant, so it complains695    // if I do. eslint-disable-next-line no-fallthrough696    case RootErrored: {697      // If this was an async render, the error may have happened due to698      // a mutation in a concurrent event. Try rendering one more time,699      // synchronously, to see if the error goes away. If there are700      // lower priority updates, let's include those, too, in case they701      // fix the inconsistency. Render at Idle to include all updates.702      // If it was Idle or Never or some not-yet-invented time, render703      // at that time.704      markRootExpiredAtTime(705        root,706        expirationTime > Idle ? Idle : expirationTime,707      );708      // We assume that this second render pass will be synchronous709      // and therefore not hit this path again.710      break;711    }712    case RootSuspended: {713      markRootSuspendedAtTime(root, expirationTime);714      const lastSuspendedTime = root.lastSuspendedTime;715      if (expirationTime === lastSuspendedTime) {716        root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork);717      }718      // We have an acceptable loading state. We need to figure out if we719      // should immediately commit it or wait a bit.720      // If we have processed new updates during this render, we may now721      // have a new loading state ready. We want to ensure that we commit722      // that as soon as possible.723      const hasNotProcessedNewUpdates =724        workInProgressRootLatestProcessedExpirationTime === Sync;725      if (726        hasNotProcessedNewUpdates &&727        // do not delay if we're inside an act() scope728        !(729          true &&730          flushSuspenseFallbacksInTests &&731          IsThisRendererActing.current732        )733      ) {734        // If we have not processed any new updates during this pass, then735        // this is either a retry of an existing fallback state or a736        // hidden tree. Hidden trees shouldn't be batched with other work737        // and after that's fixed it can only be a retry. We're going to738        // throttle committing retries so that we don't show too many739        // loading states too quickly.740        let msUntilTimeout =741          globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();742        // Don't bother with a very short suspense time.743        if (msUntilTimeout > 10) {744          if (workInProgressRootHasPendingPing) {745            const lastPingedTime = root.lastPingedTime;746            if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {747              // This render was pinged but we didn't get to restart748              // earlier so try restarting now instead.749              root.lastPingedTime = expirationTime;750              prepareFreshStack(root, expirationTime);751              break;752            }753          }754          const nextTime = getNextRootExpirationTimeToWorkOn(root);755          if (nextTime !== NoWork && nextTime !== expirationTime) {756            // There's additional work on this root.757            break;758          }759          if (760            lastSuspendedTime !== NoWork &&761            lastSuspendedTime !== expirationTime762          ) {763            // We should prefer to render the fallback of at the last764            // suspended level. Ping the last suspended level to try765            // rendering it again.766            root.lastPingedTime = lastSuspendedTime;767            break;768          }769          // The render is suspended, it hasn't timed out, and there's no770          // lower priority work to do. Instead of committing the fallback771          // immediately, wait for more data to arrive.772          root.timeoutHandle = scheduleTimeout(773            commitRoot.bind(null, root),774            msUntilTimeout,775          );776          break;777        }778      }779      // The work expired. Commit immediately.780      commitRoot(root);781      break;782    }783    case RootSuspendedWithDelay: {784      markRootSuspendedAtTime(root, expirationTime);785      const lastSuspendedTime = root.lastSuspendedTime;786      if (expirationTime === lastSuspendedTime) {787        root.nextKnownPendingLevel = getRemainingExpirationTime(finishedWork);788      }789      if (790        // do not delay if we're inside an act() scope791        !(792          true &&793          flushSuspenseFallbacksInTests &&794          IsThisRendererActing.current795        )796      ) {797        // We're suspended in a state that should be avoided. We'll try to798        // avoid committing it for as long as the timeouts let us.799        if (workInProgressRootHasPendingPing) {800          const lastPingedTime = root.lastPingedTime;801          if (lastPingedTime === NoWork || lastPingedTime >= expirationTime) {802            // This render was pinged but we didn't get to restart earlier803            // so try restarting now instead.804            root.lastPingedTime = expirationTime;805            prepareFreshStack(root, expirationTime);806            break;807          }808        }809        const nextTime = getNextRootExpirationTimeToWorkOn(root);810        if (nextTime !== NoWork && nextTime !== expirationTime) {811          // There's additional work on this root.812          break;813        }814        if (815          lastSuspendedTime !== NoWork &&816          lastSuspendedTime !== expirationTime817        ) {818          // We should prefer to render the fallback of at the last819          // suspended level. Ping the last suspended level to try820          // rendering it again.821          root.lastPingedTime = lastSuspendedTime;822          break;823        }824        let msUntilTimeout;825        if (workInProgressRootLatestSuspenseTimeout !== Sync) {826          // We have processed a suspense config whose expiration time we827          // can use as the timeout.828          msUntilTimeout =829            expirationTimeToMs(workInProgressRootLatestSuspenseTimeout) - now();830        } else if (workInProgressRootLatestProcessedExpirationTime === Sync) {831          // This should never normally happen because only new updates832          // cause delayed states, so we should have processed something.833          // However, this could also happen in an offscreen tree.834          msUntilTimeout = 0;835        } else {836          // If we don't have a suspense config, we're going to use a837          // heuristic to determine how long we can suspend.838          const eventTimeMs: number = inferTimeFromExpirationTime(839            workInProgressRootLatestProcessedExpirationTime,840          );841          const currentTimeMs = now();842          const timeUntilExpirationMs =843            expirationTimeToMs(expirationTime) - currentTimeMs;844          let timeElapsed = currentTimeMs - eventTimeMs;845          if (timeElapsed < 0) {846            // We get this wrong some time since we estimate the time.847            timeElapsed = 0;848          }849          msUntilTimeout = jnd(timeElapsed) - timeElapsed;850          // Clamp the timeout to the expiration time. TODO: Once the851          // event time is exact instead of inferred from expiration time852          // we don't need this.853          if (timeUntilExpirationMs < msUntilTimeout) {854            msUntilTimeout = timeUntilExpirationMs;855          }856        }857        // Don't bother with a very short suspense time.858        if (msUntilTimeout > 10) {859          // The render is suspended, it hasn't timed out, and there's no860          // lower priority work to do. Instead of committing the fallback861          // immediately, wait for more data to arrive.862          root.timeoutHandle = scheduleTimeout(863            commitRoot.bind(null, root),864            msUntilTimeout,865          );866          break;867        }868      }869      // The work expired. Commit immediately.870      commitRoot(root);871      break;872    }873    case RootCompleted: {874      // The work completed. Ready to commit.875      if (876        // do not delay if we're inside an act() scope877        !(878          true &&879          flushSuspenseFallbacksInTests &&880          IsThisRendererActing.current881        ) &&882        workInProgressRootLatestProcessedExpirationTime !== Sync &&883        workInProgressRootCanSuspendUsingConfig !== null884      ) {885        // If we have exceeded the minimum loading delay, which probably886        // means we have shown a spinner already, we might have to suspend887        // a bit longer to ensure that the spinner is shown for888        // enough time.889        const msUntilTimeout = computeMsUntilSuspenseLoadingDelay(890          workInProgressRootLatestProcessedExpirationTime,891          expirationTime,892          workInProgressRootCanSuspendUsingConfig,893        );894        if (msUntilTimeout > 10) {895          markRootSuspendedAtTime(root, expirationTime);896          root.timeoutHandle = scheduleTimeout(897            commitRoot.bind(null, root),898            msUntilTimeout,899          );900          break;901        }902      }903      commitRoot(root);904      break;905    }906    default: {907      invariant(false, 'Unknown root exit status.');908    }909  }910}911// This is the entry point for synchronous tasks that don't go912// through Scheduler913function performSyncWorkOnRoot(root) {914  // Check if there's expired work on this root. Otherwise, render at Sync.915  const lastExpiredTime = root.lastExpiredTime;916  const expirationTime = lastExpiredTime !== NoWork ? lastExpiredTime : Sync;917  invariant(918    (executionContext & (RenderContext | CommitContext)) === NoContext,919    'Should not already be working.',920  );921  flushPassiveEffects();922  // If the root or expiration time have changed, throw out the existing stack923  // and prepare a fresh one. Otherwise we'll continue where we left off.924  if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {925    prepareFreshStack(root, expirationTime); // åå§å workInProgress926    startWorkOnPendingInteractions(root, expirationTime);927  }928  // If we have a work-in-progress fiber, it means there's still work to do929  // in this root.930  if (workInProgress !== null) {931    const prevExecutionContext = executionContext;932    executionContext |= RenderContext;933    const prevDispatcher = pushDispatcher(root);934    const prevInteractions = pushInteractions(root);935    startWorkLoopTimer(workInProgress);936    do {937      try {938        debugger939        workLoopSync();940        break;941      } catch (thrownValue) {942        handleError(root, thrownValue);943      }944    } while (true);945    resetContextDependencies();946    executionContext = prevExecutionContext;947    popDispatcher(prevDispatcher);948    if (enableSchedulerTracing) {949      popInteractions(((prevInteractions: any): Set<Interaction>));950    }951    if (workInProgressRootExitStatus === RootFatalErrored) {952      const fatalError = workInProgressRootFatalError;953      stopInterruptedWorkLoopTimer();954      prepareFreshStack(root, expirationTime);955      markRootSuspendedAtTime(root, expirationTime);956      ensureRootIsScheduled(root);957      throw fatalError;958    }959    if (workInProgress !== null) {960      // This is a sync render, so we should have finished the whole tree.961      invariant(962        false,963        'Cannot commit an incomplete root. This error is likely caused by a ' +964          'bug in React. Please file an issue.',965      );966    } else {967      // We now have a consistent tree. Because this is a sync render, we968      // will commit it even if something suspended.969      stopFinishedWorkLoopTimer();970      root.finishedWork = (root.current.alternate: any);971      root.finishedExpirationTime = expirationTime;972      finishSyncRender(root);973    }974    // Before exiting, make sure there's a callback scheduled for the next975    // pending level.976    ensureRootIsScheduled(root);977  }978  return null;979}980function finishSyncRender(root) {981  // Set this to null to indicate there's no in-progress render.982  workInProgressRoot = null;983  debugger;984  commitRoot(root);985}986export function flushRoot(root: FiberRoot, expirationTime: ExpirationTime) {987  markRootExpiredAtTime(root, expirationTime);988  ensureRootIsScheduled(root);989  if ((executionContext & (RenderContext | CommitContext)) === NoContext) {990    flushSyncCallbackQueue();991  }992}993export function flushDiscreteUpdates() {994  // TODO: Should be able to flush inside batchedUpdates, but not inside `act`.995  // However, `act` uses `batchedUpdates`, so there's no way to distinguish996  // those two cases. Need to fix this before exposing flushDiscreteUpdates997  // as a public API.998  if (999    (executionContext & (BatchedContext | RenderContext | CommitContext)) !==1000    NoContext1001  ) {1002    if (true) {1003      if ((executionContext & RenderContext) !== NoContext) {1004        console.error(1005          'unstable_flushDiscreteUpdates: Cannot flush updates when React is ' +1006            'already rendering.',1007        );1008      }1009    }1010    // We're already rendering, so we can't synchronously flush pending work.1011    // This is probably a nested event dispatch triggered by a lifecycle/effect,1012    // like `el.focus()`. Exit.1013    return;1014  }1015  flushPendingDiscreteUpdates();1016  // If the discrete updates scheduled passive effects, flush them now so that1017  // they fire before the next serial event.1018  flushPassiveEffects();1019}1020export function deferredUpdates<A>(fn: () => A): A {1021  // TODO: Remove in favor of Scheduler.next1022  return runWithPriority(NormalPriority, fn);1023}1024export function syncUpdates<A, B, C, R>(1025  fn: (A, B, C) => R,1026  a: A,1027  b: B,1028  c: C,1029): R {1030  return runWithPriority(ImmediatePriority, fn.bind(null, a, b, c));1031}1032function flushPendingDiscreteUpdates() {1033  if (rootsWithPendingDiscreteUpdates !== null) {1034    // For each root with pending discrete updates, schedule a callback to1035    // immediately flush them.1036    const roots = rootsWithPendingDiscreteUpdates;1037    rootsWithPendingDiscreteUpdates = null;1038    roots.forEach((expirationTime, root) => {1039      markRootExpiredAtTime(root, expirationTime);1040      ensureRootIsScheduled(root);1041    });1042    // Now flush the immediate queue.1043    flushSyncCallbackQueue();1044  }1045}1046export function batchedUpdates<A, R>(fn: A => R, a: A): R {1047  const prevExecutionContext = executionContext;1048  executionContext |= BatchedContext;1049  try {1050    return fn(a);1051  } finally {1052    executionContext = prevExecutionContext;1053    if (executionContext === NoContext) {1054      // Flush the immediate callbacks that were scheduled during this batch1055      flushSyncCallbackQueue();1056    }1057  }1058}1059export function batchedEventUpdates<A, R>(fn: A => R, a: A): R {1060  const prevExecutionContext = executionContext;1061  executionContext |= EventContext;1062  try {1063    return fn(a);1064  } finally {1065    executionContext = prevExecutionContext;1066    if (executionContext === NoContext) {1067      // Flush the immediate callbacks that were scheduled during this batch1068      flushSyncCallbackQueue();1069    }1070  }1071}1072export function discreteUpdates<A, B, C, D, R>(1073  fn: (A, B, C) => R,1074  a: A,1075  b: B,1076  c: C,1077  d: D,1078): R {1079  const prevExecutionContext = executionContext;1080  executionContext |= DiscreteEventContext;1081  try {1082    // Should this1083    return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c, d));1084  } finally {1085    executionContext = prevExecutionContext;1086    if (executionContext === NoContext) {1087      // Flush the immediate callbacks that were scheduled during this batch1088      flushSyncCallbackQueue();1089    }1090  }1091}1092export function unbatchedUpdates<A, R>(fn: (a: A) => R, a: A): R {1093  const prevExecutionContext = executionContext;1094  executionContext &= ~BatchedContext;1095  executionContext |= LegacyUnbatchedContext;1096  try {1097    return fn(a);1098  } finally {1099    executionContext = prevExecutionContext;1100    if (executionContext === NoContext) {1101      // Flush the immediate callbacks that were scheduled during this batch1102      flushSyncCallbackQueue();1103    }1104  }1105}1106export function flushSync<A, R>(fn: A => R, a: A): R {1107  if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {1108    invariant(1109      false,1110      'flushSync was called from inside a lifecycle method. It cannot be ' +1111        'called when React is already rendering.',1112    );1113  }1114  const prevExecutionContext = executionContext;1115  executionContext |= BatchedContext;1116  try {1117    return runWithPriority(ImmediatePriority, fn.bind(null, a));1118  } finally {1119    executionContext = prevExecutionContext;1120    // Flush the immediate callbacks that were scheduled during this batch.1121    // Note that this will happen even if batchedUpdates is higher up1122    // the stack.1123    flushSyncCallbackQueue();1124  }1125}1126export function flushControlled(fn: () => mixed): void {1127  const prevExecutionContext = executionContext;1128  executionContext |= BatchedContext;1129  try {1130    runWithPriority(ImmediatePriority, fn);1131  } finally {1132    executionContext = prevExecutionContext;1133    if (executionContext === NoContext) {1134      // Flush the immediate callbacks that were scheduled during this batch1135      flushSyncCallbackQueue();1136    }1137  }1138}1139function prepareFreshStack(root, expirationTime) {1140  root.finishedWork = null;1141  root.finishedExpirationTime = NoWork;1142  const timeoutHandle = root.timeoutHandle;1143  if (timeoutHandle !== noTimeout) {1144    // The root previous suspended and scheduled a timeout to commit a fallback1145    // state. Now that we have additional work, cancel the timeout.1146    root.timeoutHandle = noTimeout;1147    // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above1148    cancelTimeout(timeoutHandle);1149  }1150  if (workInProgress !== null) {1151    let interruptedWork = workInProgress.return;1152    while (interruptedWork !== null) {1153      unwindInterruptedWork(interruptedWork);1154      interruptedWork = interruptedWork.return;1155    }1156  }1157  workInProgressRoot = root;1158  debugger1159  workInProgress = createWorkInProgress(root.current, null);1160  renderExpirationTime = expirationTime;1161  workInProgressRootExitStatus = RootIncomplete;1162  workInProgressRootFatalError = null;1163  workInProgressRootLatestProcessedExpirationTime = Sync;1164  workInProgressRootLatestSuspenseTimeout = Sync;1165  workInProgressRootCanSuspendUsingConfig = null;1166  workInProgressRootNextUnprocessedUpdateTime = NoWork;1167  workInProgressRootHasPendingPing = false;1168  if (enableSchedulerTracing) {1169    spawnedWorkDuringRender = null;1170  }1171  if (true) {1172    ReactStrictModeWarnings.discardPendingWarnings();1173  }1174}1175function handleError(root, thrownValue) {1176  do {1177    try {1178      // Reset module-level state that was set during the render phase.1179      resetContextDependencies();1180      resetHooksAfterThrow();1181      resetCurrentDebugFiberInDEV();1182      if (workInProgress === null || workInProgress.return === null) {1183        // Expected to be working on a non-root fiber. This is a fatal error1184        // because there's no ancestor that can handle it; the root is1185        // supposed to capture all errors that weren't caught by an error1186        // boundary.1187        workInProgressRootExitStatus = RootFatalErrored;1188        workInProgressRootFatalError = thrownValue;1189        // Set `workInProgress` to null. This represents advancing to the next1190        // sibling, or the parent if there are no siblings. But since the root1191        // has no siblings nor a parent, we set it to null. Usually this is1192        // handled by `completeUnitOfWork` or `unwindWork`, but since we're1193        // interntionally not calling those, we need set it here.1194        // TODO: Consider calling `unwindWork` to pop the contexts.1195        workInProgress = null;1196        return null;1197      }1198      if (enableProfilerTimer && workInProgress.mode & ProfileMode) {1199        // Record the time spent rendering before an error was thrown. This1200        // avoids inaccurate Profiler durations in the case of a1201        // suspended render.1202        stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);1203      }1204      throwException(1205        root,1206        workInProgress.return,1207        workInProgress,1208        thrownValue,1209        renderExpirationTime,1210      );1211      workInProgress = completeUnitOfWork(workInProgress);1212    } catch (yetAnotherThrownValue) {1213      // Something in the return path also threw.1214      thrownValue = yetAnotherThrownValue;1215      continue;1216    }1217    // Return to the normal work loop.1218    return;1219  } while (true);1220}1221function pushDispatcher(root) {1222  const prevDispatcher = ReactCurrentDispatcher.current;1223  ReactCurrentDispatcher.current = ContextOnlyDispatcher;1224  if (prevDispatcher === null) {1225    // The React isomorphic package does not include a default dispatcher.1226    // Instead the first renderer will lazily attach one, in order to give1227    // nicer error messages.1228    return ContextOnlyDispatcher;1229  } else {1230    return prevDispatcher;1231  }1232}1233function popDispatcher(prevDispatcher) {1234  ReactCurrentDispatcher.current = prevDispatcher;1235}1236function pushInteractions(root) {1237  if (enableSchedulerTracing) {1238    const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1239    __interactionsRef.current = root.memoizedInteractions;1240    return prevInteractions;1241  }1242  return null;1243}1244function popInteractions(prevInteractions) {1245  if (enableSchedulerTracing) {1246    __interactionsRef.current = prevInteractions;1247  }1248}1249export function markCommitTimeOfFallback() {1250  globalMostRecentFallbackTime = now();1251}1252export function markRenderEventTimeAndConfig(1253  expirationTime: ExpirationTime,1254  suspenseConfig: null | SuspenseConfig,1255): void {1256  if (1257    expirationTime < workInProgressRootLatestProcessedExpirationTime &&1258    expirationTime > Idle1259  ) {1260    workInProgressRootLatestProcessedExpirationTime = expirationTime;1261  }1262  if (suspenseConfig !== null) {1263    if (1264      expirationTime < workInProgressRootLatestSuspenseTimeout &&1265      expirationTime > Idle1266    ) {1267      workInProgressRootLatestSuspenseTimeout = expirationTime;1268      // Most of the time we only have one config and getting wrong is not bad.1269      workInProgressRootCanSuspendUsingConfig = suspenseConfig;1270    }1271  }1272}1273export function markUnprocessedUpdateTime(1274  expirationTime: ExpirationTime,1275): void {1276  if (expirationTime > workInProgressRootNextUnprocessedUpdateTime) {1277    workInProgressRootNextUnprocessedUpdateTime = expirationTime;1278  }1279}1280export function renderDidSuspend(): void {1281  if (workInProgressRootExitStatus === RootIncomplete) {1282    workInProgressRootExitStatus = RootSuspended;1283  }1284}1285export function renderDidSuspendDelayIfPossible(): void {1286  if (1287    workInProgressRootExitStatus === RootIncomplete ||1288    workInProgressRootExitStatus === RootSuspended1289  ) {1290    workInProgressRootExitStatus = RootSuspendedWithDelay;1291  }1292  // Check if there's a lower priority update somewhere else in the tree.1293  if (1294    workInProgressRootNextUnprocessedUpdateTime !== NoWork &&1295    workInProgressRoot !== null1296  ) {1297    // Mark the current render as suspended, and then mark that there's a1298    // pending update.1299    // TODO: This should immediately interrupt the current render, instead1300    // of waiting until the next time we yield.1301    markRootSuspendedAtTime(workInProgressRoot, renderExpirationTime);1302    markRootUpdatedAtTime(1303      workInProgressRoot,1304      workInProgressRootNextUnprocessedUpdateTime,1305    );1306  }1307}1308export function renderDidError() {1309  if (workInProgressRootExitStatus !== RootCompleted) {1310    workInProgressRootExitStatus = RootErrored;1311  }1312}1313// Called during render to determine if anything has suspended.1314// Returns false if we're not sure.1315export function renderHasNotSuspendedYet(): boolean {1316  // If something errored or completed, we can't really be sure,1317  // so those are false.1318  return workInProgressRootExitStatus === RootIncomplete;1319}1320function inferTimeFromExpirationTime(expirationTime: ExpirationTime): number {1321  // We don't know exactly when the update was scheduled, but we can infer an1322  // approximate start time from the expiration time.1323  const earliestExpirationTimeMs = expirationTimeToMs(expirationTime);1324  return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;1325}1326function inferTimeFromExpirationTimeWithSuspenseConfig(1327  expirationTime: ExpirationTime,1328  suspenseConfig: SuspenseConfig,1329): number {1330  // We don't know exactly when the update was scheduled, but we can infer an1331  // approximate start time from the expiration time by subtracting the timeout1332  // that was added to the event time.1333  const earliestExpirationTimeMs = expirationTimeToMs(expirationTime);1334  return (1335    earliestExpirationTimeMs -1336    (suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION)1337  );1338}1339// The work loop is an extremely hot path. Tell Closure not to inline it.1340/** @noinline */1341function workLoopSync() {1342  // Already timed out, so perform work without checking if we need to yield.1343  while (workInProgress !== null) {1344    debugger1345    workInProgress = performUnitOfWork(workInProgress);1346  }1347}1348/** @noinline */1349function workLoopConcurrent() {1350  // Perform work until Scheduler asks us to yield1351  while (workInProgress !== null && !shouldYield()) {1352    workInProgress = performUnitOfWork(workInProgress);1353  }1354}1355function performUnitOfWork(unitOfWork: Fiber): Fiber | null {1356  // The current, flushed, state of this fiber is the alternate. Ideally1357  // nothing should rely on this, but relying on it here means that we don't1358  // need an additional field on the work in progress.1359  const current = unitOfWork.alternate;1360  1361  startWorkTimer(unitOfWork);1362  setCurrentDebugFiberInDEV(unitOfWork);1363  let next;1364  if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {1365    startProfilerTimer(unitOfWork);1366    debugger;1367    next = beginWork(current, unitOfWork, renderExpirationTime);1368    stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);1369  } else {1370    next = beginWork(current, unitOfWork, renderExpirationTime);1371  }1372  resetCurrentDebugFiberInDEV();1373  unitOfWork.memoizedProps = unitOfWork.pendingProps;1374  if (next === null) {1375    // If this doesn't spawn new work, complete the current work.1376    next = completeUnitOfWork(unitOfWork);1377  }1378  console.log(next)1379  ReactCurrentOwner.current = null;1380  return next;1381}1382function completeUnitOfWork(unitOfWork: Fiber): Fiber | null {1383  // Attempt to complete the current unit of work, then move to the next1384  // sibling. If there are no more siblings, return to the parent fiber.1385  workInProgress = unitOfWork;1386  do {1387    // The current, flushed, state of this fiber is the alternate. Ideally1388    // nothing should rely on this, but relying on it here means that we don't1389    // need an additional field on the work in progress.1390    const current = workInProgress.alternate;1391    const returnFiber = workInProgress.return;1392    // Check if the work completed or if something threw.1393    if ((workInProgress.effectTag & Incomplete) === NoEffect) {1394      setCurrentDebugFiberInDEV(workInProgress);1395      let next;1396      if (1397        !enableProfilerTimer ||1398        (workInProgress.mode & ProfileMode) === NoMode1399      ) {1400        next = completeWork(current, workInProgress, renderExpirationTime);1401      } else {1402        startProfilerTimer(workInProgress);1403        next = completeWork(current, workInProgress, renderExpirationTime);1404        // Update render duration assuming we didn't error.1405        stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);1406      }1407      stopWorkTimer(workInProgress);1408      resetCurrentDebugFiberInDEV();1409      resetChildExpirationTime(workInProgress);1410      if (next !== null) {1411        // Completing this fiber spawned new work. Work on that next.1412        return next;1413      }1414      if (1415        returnFiber !== null &&1416        // Do not append effects to parents if a sibling failed to complete1417        (returnFiber.effectTag & Incomplete) === NoEffect1418      ) {1419        // Append all the effects of the subtree and this fiber onto the effect1420        // list of the parent. The completion order of the children affects the1421        // side-effect order.1422        if (returnFiber.firstEffect === null) {1423          returnFiber.firstEffect = workInProgress.firstEffect;1424        }1425        if (workInProgress.lastEffect !== null) {1426          if (returnFiber.lastEffect !== null) {1427            returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;1428          }1429          returnFiber.lastEffect = workInProgress.lastEffect;1430        }1431        // If this fiber had side-effects, we append it AFTER the children's1432        // side-effects. We can perform certain side-effects earlier if needed,1433        // by doing multiple passes over the effect list. We don't want to1434        // schedule our own side-effect on our own list because if end up1435        // reusing children we'll schedule this effect onto itself since we're1436        // at the end.1437        const effectTag = workInProgress.effectTag;1438        // Skip both NoWork and PerformedWork tags when creating the effect1439        // list. PerformedWork effect is read by React DevTools but shouldn't be1440        // committed.1441        if (effectTag > PerformedWork) {1442          if (returnFiber.lastEffect !== null) {1443            returnFiber.lastEffect.nextEffect = workInProgress;1444          } else {1445            returnFiber.firstEffect = workInProgress;1446          }1447          returnFiber.lastEffect = workInProgress;1448        }1449      }1450    } else {1451      // This fiber did not complete because something threw. Pop values off1452      // the stack without entering the complete phase. If this is a boundary,1453      // capture values if possible.1454      const next = unwindWork(workInProgress, renderExpirationTime);1455      // Because this fiber did not complete, don't reset its expiration time.1456      if (1457        enableProfilerTimer &&1458        (workInProgress.mode & ProfileMode) !== NoMode1459      ) {1460        // Record the render duration for the fiber that errored.1461        stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);1462        // Include the time spent working on failed children before continuing.1463        let actualDuration = workInProgress.actualDuration;1464        let child = workInProgress.child;1465        while (child !== null) {1466          actualDuration += child.actualDuration;1467          child = child.sibling;1468        }1469        workInProgress.actualDuration = actualDuration;1470      }1471      if (next !== null) {1472        // If completing this work spawned new work, do that next. We'll come1473        // back here again.1474        // Since we're restarting, remove anything that is not a host effect1475        // from the effect tag.1476        // TODO: The name stopFailedWorkTimer is misleading because Suspense1477        // also captures and restarts.1478        stopFailedWorkTimer(workInProgress);1479        next.effectTag &= HostEffectMask;1480        return next;1481      }1482      stopWorkTimer(workInProgress);1483      if (returnFiber !== null) {1484        // Mark the parent fiber as incomplete and clear its effect list.1485        returnFiber.firstEffect = returnFiber.lastEffect = null;1486        returnFiber.effectTag |= Incomplete;1487      }1488    }1489    const siblingFiber = workInProgress.sibling;1490    if (siblingFiber !== null) {1491      // If there is more work to do in this returnFiber, do that next.1492      return siblingFiber;1493    }1494    // Otherwise, return to the parent1495    workInProgress = returnFiber;1496  } while (workInProgress !== null);1497  // We've reached the root.1498  if (workInProgressRootExitStatus === RootIncomplete) {1499    workInProgressRootExitStatus = RootCompleted;1500  }1501  return null;1502}1503function getRemainingExpirationTime(fiber: Fiber) {1504  const updateExpirationTime = fiber.expirationTime;1505  const childExpirationTime = fiber.childExpirationTime;1506  return updateExpirationTime > childExpirationTime1507    ? updateExpirationTime1508    : childExpirationTime;1509}1510function resetChildExpirationTime(completedWork: Fiber) {1511  if (1512    renderExpirationTime !== Never &&1513    completedWork.childExpirationTime === Never1514  ) {1515    // The children of this component are hidden. Don't bubble their1516    // expiration times.1517    return;1518  }1519  let newChildExpirationTime = NoWork;1520  // Bubble up the earliest expiration time.1521  if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {1522    // In profiling mode, resetChildExpirationTime is also used to reset1523    // profiler durations.1524    let actualDuration = completedWork.actualDuration;1525    let treeBaseDuration = completedWork.selfBaseDuration;1526    // When a fiber is cloned, its actualDuration is reset to 0. This value will1527    // only be updated if work is done on the fiber (i.e. it doesn't bailout).1528    // When work is done, it should bubble to the parent's actualDuration. If1529    // the fiber has not been cloned though, (meaning no work was done), then1530    // this value will reflect the amount of time spent working on a previous1531    // render. In that case it should not bubble. We determine whether it was1532    // cloned by comparing the child pointer.1533    const shouldBubbleActualDurations =1534      completedWork.alternate === null ||1535      completedWork.child !== completedWork.alternate.child;1536    let child = completedWork.child;1537    while (child !== null) {1538      const childUpdateExpirationTime = child.expirationTime;1539      const childChildExpirationTime = child.childExpirationTime;1540      if (childUpdateExpirationTime > newChildExpirationTime) {1541        newChildExpirationTime = childUpdateExpirationTime;1542      }1543      if (childChildExpirationTime > newChildExpirationTime) {1544        newChildExpirationTime = childChildExpirationTime;1545      }1546      if (shouldBubbleActualDurations) {1547        actualDuration += child.actualDuration;1548      }1549      treeBaseDuration += child.treeBaseDuration;1550      child = child.sibling;1551    }1552    completedWork.actualDuration = actualDuration;1553    completedWork.treeBaseDuration = treeBaseDuration;1554  } else {1555    let child = completedWork.child;1556    while (child !== null) {1557      const childUpdateExpirationTime = child.expirationTime;1558      const childChildExpirationTime = child.childExpirationTime;1559      if (childUpdateExpirationTime > newChildExpirationTime) {1560        newChildExpirationTime = childUpdateExpirationTime;1561      }1562      if (childChildExpirationTime > newChildExpirationTime) {1563        newChildExpirationTime = childChildExpirationTime;1564      }1565      child = child.sibling;1566    }1567  }1568  completedWork.childExpirationTime = newChildExpirationTime;1569}1570function commitRoot(root) {1571  const renderPriorityLevel = getCurrentPriorityLevel();1572  runWithPriority(1573    ImmediatePriority,1574    commitRootImpl.bind(null, root, renderPriorityLevel),1575  );1576  return null;1577}1578function commitRootImpl(root, renderPriorityLevel) {1579  do {1580    // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1581    // means `flushPassiveEffects` will sometimes result in additional1582    // passive effects. So we need to keep flushing in a loop until there are1583    // no more pending effects.1584    // TODO: Might be better if `flushPassiveEffects` did not automatically1585    // flush synchronous work at the end, to avoid factoring hazards like this.1586    debugger1587    flushPassiveEffects();1588  } while (rootWithPendingPassiveEffects !== null);1589  flushRenderPhaseStrictModeWarningsInDEV();1590  invariant(1591    (executionContext & (RenderContext | CommitContext)) === NoContext,1592    'Should not already be working.',1593  );1594  const finishedWork = root.finishedWork;1595  const expirationTime = root.finishedExpirationTime;1596  if (finishedWork === null) {1597    return null;1598  }1599  root.finishedWork = null;1600  root.finishedExpirationTime = NoWork;1601  invariant(1602    finishedWork !== root.current,1603    'Cannot commit the same tree as before. This error is likely caused by ' +1604      'a bug in React. Please file an issue.',1605  );1606  // commitRoot never returns a continuation; it always finishes synchronously.1607  // So we can clear these now to allow a new callback to be scheduled.1608  root.callbackNode = null;1609  root.callbackExpirationTime = NoWork;1610  root.callbackPriority = NoPriority;1611  root.nextKnownPendingLevel = NoWork;1612  startCommitTimer();1613  // Update the first and last pending times on this root. The new first1614  // pending time is whatever is left on the root fiber.1615  const remainingExpirationTimeBeforeCommit = getRemainingExpirationTime(1616    finishedWork,1617  );1618  markRootFinishedAtTime(1619    root,1620    expirationTime,1621    remainingExpirationTimeBeforeCommit,1622  );1623  if (root === workInProgressRoot) {1624    // We can reset these now that they are finished.1625    workInProgressRoot = null;1626    workInProgress = null;1627    renderExpirationTime = NoWork;1628  } else {1629    // This indicates that the last root we worked on is not the same one that1630    // we're committing now. This most commonly happens when a suspended root1631    // times out.1632  }1633  // Get the list of effects.1634  let firstEffect;1635  if (finishedWork.effectTag > PerformedWork) {1636    // A fiber's effect list consists only of its children, not itself. So if1637    // the root has an effect, we need to add it to the end of the list. The1638    // resulting list is the set that would belong to the root's parent, if it1639    // had one; that is, all the effects in the tree including the root.1640    if (finishedWork.lastEffect !== null) {1641      finishedWork.lastEffect.nextEffect = finishedWork;1642      firstEffect = finishedWork.firstEffect;1643    } else {1644      firstEffect = finishedWork;1645    }1646  } else {1647    // There is no effect on the root.1648    firstEffect = finishedWork.firstEffect;1649  }1650  if (firstEffect !== null) { // èµ°è¿é1651    const prevExecutionContext = executionContext;1652    executionContext |= CommitContext;1653    const prevInteractions = pushInteractions(root);1654    // Reset this to null before calling lifecycles1655    ReactCurrentOwner.current = null;1656    // The commit phase is broken into several sub-phases. We do a separate pass1657    // of the effect list for each phase: all mutation effects come before all1658    // layout effects, and so on.1659    // The first phase a "before mutation" phase. We use this phase to read the1660    // state of the host tree right before we mutate it. This is where1661    // getSnapshotBeforeUpdate is called.1662    startCommitSnapshotEffectsTimer();1663    prepareForCommit(root.containerInfo);1664    nextEffect = firstEffect;1665    do {1666      if (false) {1667        1668      } else {1669        try {1670          debugger1671          commitBeforeMutationEffects();1672        } catch (error) {1673          invariant(nextEffect !== null, 'Should be working on an effect.');1674          captureCommitPhaseError(nextEffect, error);1675          nextEffect = nextEffect.nextEffect;1676        }1677      }1678    } while (nextEffect !== null);1679    stopCommitSnapshotEffectsTimer();1680    if (enableProfilerTimer) {1681      // Mark the current commit time to be shared by all Profilers in this1682      // batch. This enables them to be grouped later.1683      recordCommitTime();1684    }1685    // The next phase is the mutation phase, where we mutate the host tree.1686    startCommitHostEffectsTimer();1687    nextEffect = firstEffect;1688    do {1689      if (false) {1690        1691      } else {1692        try {1693          debugger1694          commitMutationEffects(root, renderPriorityLevel);1695        } catch (error) {1696          invariant(nextEffect !== null, 'Should be working on an effect.');1697          captureCommitPhaseError(nextEffect, error);1698          nextEffect = nextEffect.nextEffect;1699        }1700      }1701    } while (nextEffect !== null);1702    stopCommitHostEffectsTimer();1703    resetAfterCommit(root.containerInfo);1704    // The work-in-progress tree is now the current tree. This must come after1705    // the mutation phase, so that the previous tree is still current during1706    // componentWillUnmount, but before the layout phase, so that the finished1707    // work is current during componentDidMount/Update.1708    root.current = finishedWork;1709    // The next phase is the layout phase, where we call effects that read1710    // the host tree after it's been mutated. The idiomatic use case for this is1711    // layout, but class component lifecycles also fire here for legacy reasons.1712    startCommitLifeCyclesTimer();1713    nextEffect = firstEffect;1714    do {1715      if (false) {1716        1717      } else {1718        try {1719          debugger1720          commitLayoutEffects(root, expirationTime);1721        } catch (error) {1722          invariant(nextEffect !== null, 'Should be working on an effect.');1723          captureCommitPhaseError(nextEffect, error);1724          nextEffect = nextEffect.nextEffect;1725        }1726      }1727    } while (nextEffect !== null);1728    stopCommitLifeCyclesTimer();1729    nextEffect = null;1730    // Tell Scheduler to yield at the end of the frame, so the browser has an1731    // opportunity to paint.1732    requestPaint();1733    if (enableSchedulerTracing) {1734      popInteractions(((prevInteractions: any): Set<Interaction>));1735    }1736    executionContext = prevExecutionContext;1737  } else {1738    // No effects.1739    root.current = finishedWork;1740    // Measure these anyway so the flamegraph explicitly shows that there were1741    // no effects.1742    // TODO: Maybe there's a better way to report this.1743    startCommitSnapshotEffectsTimer();1744    stopCommitSnapshotEffectsTimer();1745    if (enableProfilerTimer) {1746      recordCommitTime();1747    }1748    startCommitHostEffectsTimer();1749    stopCommitHostEffectsTimer();1750    startCommitLifeCyclesTimer();1751    stopCommitLifeCyclesTimer();1752  }1753  stopCommitTimer();1754  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1755  if (rootDoesHavePassiveEffects) {1756    // This commit has passive effects. Stash a reference to them. But don't1757    // schedule a callback until after flushing layout work.1758    rootDoesHavePassiveEffects = false;1759    rootWithPendingPassiveEffects = root;1760    pendingPassiveEffectsExpirationTime = expirationTime;1761    pendingPassiveEffectsRenderPriority = renderPriorityLevel;1762  } else {1763    // We are done with the effect chain at this point so let's clear the1764    // nextEffect pointers to assist with GC. If we have passive effects, we'll1765    // clear this in flushPassiveEffects.1766    nextEffect = firstEffect;1767    while (nextEffect !== null) {1768      const nextNextEffect = nextEffect.nextEffect;1769      nextEffect.nextEffect = null;1770      nextEffect = nextNextEffect;1771    }1772  }1773  // Check if there's remaining work on this root1774  const remainingExpirationTime = root.firstPendingTime;1775  if (remainingExpirationTime !== NoWork) {1776    if (enableSchedulerTracing) {1777      if (spawnedWorkDuringRender !== null) {1778        const expirationTimes = spawnedWorkDuringRender;1779        spawnedWorkDuringRender = null;1780        for (let i = 0; i < expirationTimes.length; i++) {1781          scheduleInteractions(1782            root,1783            expirationTimes[i],1784            root.memoizedInteractions,1785          );1786        }1787      }1788      schedulePendingInteractions(root, remainingExpirationTime);1789    }1790  } else {1791    // If there's no remaining work, we can clear the set of already failed1792    // error boundaries.1793    legacyErrorBoundariesThatAlreadyFailed = null;1794  }1795  if (enableSchedulerTracing) {1796    if (!rootDidHavePassiveEffects) {1797      // If there are no passive effects, then we can complete the pending interactions.1798      // Otherwise, we'll wait until after the passive effects are flushed.1799      // Wait to do this until after remaining work has been scheduled,1800      // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1801      finishPendingInteractions(root, expirationTime);1802    }1803  }1804  if (remainingExpirationTime === Sync) {1805    // Count the number of times the root synchronously re-renders without1806    // finishing. If there are too many, it indicates an infinite update loop.1807    if (root === rootWithNestedUpdates) {1808      nestedUpdateCount++;1809    } else {1810      nestedUpdateCount = 0;1811      rootWithNestedUpdates = root;1812    }1813  } else {1814    nestedUpdateCount = 0;1815  }1816  onCommitRoot(finishedWork.stateNode, expirationTime);1817  // Always call this before exiting `commitRoot`, to ensure that any1818  // additional work on this root is scheduled.1819  ensureRootIsScheduled(root);1820  if (hasUncaughtError) {1821    hasUncaughtError = false;1822    const error = firstUncaughtError;1823    firstUncaughtError = null;1824    throw error;1825  }1826  if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1827    // This is a legacy edge case. We just committed the initial mount of1828    // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1829    // synchronously, but layout updates should be deferred until the end1830    // of the batch.1831    return null;1832  }1833  // If layout work was scheduled, flush it now.1834  flushSyncCallbackQueue();1835  return null;1836}1837function commitBeforeMutationEffects() {1838  while (nextEffect !== null) {1839    const effectTag = nextEffect.effectTag;1840    if ((effectTag & Snapshot) !== NoEffect) {1841      setCurrentDebugFiberInDEV(nextEffect);1842      recordEffect();1843      const current = nextEffect.alternate;1844      commitBeforeMutationEffectOnFiber(current, nextEffect);1845      resetCurrentDebugFiberInDEV();1846    }1847    if ((effectTag & Passive) !== NoEffect) {1848      // If there are passive effects, schedule a callback to flush at1849      // the earliest opportunity.1850      if (!rootDoesHavePassiveEffects) {1851        rootDoesHavePassiveEffects = true;1852        scheduleCallback(NormalPriority, () => {1853          flushPassiveEffects();1854          return null;1855        });1856      }1857    }1858    nextEffect = nextEffect.nextEffect;1859  }1860}1861function commitMutationEffects(root: FiberRoot, renderPriorityLevel) {1862  // TODO: Should probably move the bulk of this function to commitWork.1863  while (nextEffect !== null) {1864    setCurrentDebugFiberInDEV(nextEffect);1865    const effectTag = nextEffect.effectTag;1866    if (effectTag & ContentReset) {1867      commitResetTextContent(nextEffect);1868    }1869    if (effectTag & Ref) {1870      const current = nextEffect.alternate;1871      if (current !== null) {1872        commitDetachRef(current);1873      }1874    }1875    // The following switch statement is only concerned about placement,1876    // updates, and deletions. To avoid needing to add a case for every possible1877    // bitmap value, we remove the secondary effects from the effect tag and1878    // switch on that value.1879    let primaryEffectTag =1880      effectTag & (Placement | Update | Deletion | Hydrating);1881    switch (primaryEffectTag) {1882      case Placement: {1883        commitPlacement(nextEffect);1884        // Clear the "placement" from effect tag so that we know that this is1885        // inserted, before any life-cycles like componentDidMount gets called.1886        // TODO: findDOMNode doesn't rely on this any more but isMounted does1887        // and isMounted is deprecated anyway so we should be able to kill this.1888        nextEffect.effectTag &= ~Placement;1889        break;1890      }1891      case PlacementAndUpdate: {1892        // Placement1893        commitPlacement(nextEffect);1894        // Clear the "placement" from effect tag so that we know that this is1895        // inserted, before any life-cycles like componentDidMount gets called.1896        nextEffect.effectTag &= ~Placement;1897        // Update1898        const current = nextEffect.alternate;1899        commitWork(current, nextEffect);1900        break;1901      }1902      case Hydrating: {1903        nextEffect.effectTag &= ~Hydrating;1904        break;1905      }1906      case HydratingAndUpdate: {1907        nextEffect.effectTag &= ~Hydrating;1908        // Update1909        const current = nextEffect.alternate;1910        commitWork(current, nextEffect);1911        break;1912      }1913      case Update: {1914        const current = nextEffect.alternate;1915        commitWork(current, nextEffect);1916        break;1917      }1918      case Deletion: {1919        commitDeletion(root, nextEffect, renderPriorityLevel);1920        break;1921      }1922    }1923    // TODO: Only record a mutation effect if primaryEffectTag is non-zero.1924    recordEffect();1925    resetCurrentDebugFiberInDEV();1926    nextEffect = nextEffect.nextEffect;1927  }1928}1929function commitLayoutEffects(1930  root: FiberRoot,1931  committedExpirationTime: ExpirationTime,1932) {1933  // TODO: Should probably move the bulk of this function to commitWork.1934  while (nextEffect !== null) {1935    setCurrentDebugFiberInDEV(nextEffect);1936    const effectTag = nextEffect.effectTag;1937    if (effectTag & (Update | Callback)) {1938      recordEffect();1939      const current = nextEffect.alternate;1940      commitLayoutEffectOnFiber(1941        root,1942        current,1943        nextEffect,1944        committedExpirationTime,1945      );1946    }1947    if (effectTag & Ref) {1948      recordEffect();1949      commitAttachRef(nextEffect);1950    }1951    resetCurrentDebugFiberInDEV();1952    nextEffect = nextEffect.nextEffect;1953  }1954}1955export function flushPassiveEffects() {1956  if (pendingPassiveEffectsRenderPriority !== NoPriority) {1957    const priorityLevel =1958      pendingPassiveEffectsRenderPriority > NormalPriority1959        ? NormalPriority1960        : pendingPassiveEffectsRenderPriority;1961    pendingPassiveEffectsRenderPriority = NoPriority;1962    return runWithPriority(priorityLevel, flushPassiveEffectsImpl);1963  }1964}1965export function enqueuePendingPassiveHookEffectMount(1966  fiber: Fiber,1967  effect: HookEffect,1968): void {1969  if (runAllPassiveEffectDestroysBeforeCreates) {1970    pendingPassiveHookEffectsMount.push(effect, fiber);1971    if (!rootDoesHavePassiveEffects) {1972      rootDoesHavePassiveEffects = true;1973      scheduleCallback(NormalPriority, () => {1974        flushPassiveEffects();1975        return null;1976      });1977    }1978  }1979}1980export function enqueuePendingPassiveHookEffectUnmount(1981  fiber: Fiber,1982  effect: HookEffect,1983): void {1984  if (runAllPassiveEffectDestroysBeforeCreates) {1985    pendingPassiveHookEffectsUnmount.push(effect, fiber);1986    if (!rootDoesHavePassiveEffects) {1987      rootDoesHavePassiveEffects = true;1988      scheduleCallback(NormalPriority, () => {1989        flushPassiveEffects();1990        return null;1991      });1992    }1993  }1994}1995function invokePassiveEffectCreate(effect: HookEffect): void {1996  const create = effect.create;1997  effect.destroy = create();1998}1999function flushPassiveEffectsImpl() {2000  if (rootWithPendingPassiveEffects === null) {2001    return false;2002  }2003  const root = rootWithPendingPassiveEffects;2004  const expirationTime = pendingPassiveEffectsExpirationTime;2005  rootWithPendingPassiveEffects = null;2006  pendingPassiveEffectsExpirationTime = NoWork;2007  invariant(2008    (executionContext & (RenderContext | CommitContext)) === NoContext,2009    'Cannot flush passive effects while already rendering.',2010  );2011  const prevExecutionContext = executionContext;2012  executionContext |= CommitContext;2013  const prevInteractions = pushInteractions(root);2014  if (runAllPassiveEffectDestroysBeforeCreates) {2015    // It's important that ALL pending passive effect destroy functions are called2016    // before ANY passive effect create functions are called.2017    // Otherwise effects in sibling components might interfere with each other.2018    // e.g. a destroy function in one component may unintentionally override a ref2019    // value set by a create function in another component.2020    // Layout effects have the same constraint.2021    // First pass: Destroy stale passive effects.2022    let unmountEffects = pendingPassiveHookEffectsUnmount;2023    pendingPassiveHookEffectsUnmount = [];2024    for (let i = 0; i < unmountEffects.length; i += 2) {2025      const effect = ((unmountEffects[i]: any): HookEffect);2026      const fiber = ((unmountEffects[i + 1]: any): Fiber);2027      const destroy = effect.destroy;2028      effect.destroy = undefined;2029      if (typeof destroy === 'function') {2030        if (true) {2031          setCurrentDebugFiberInDEV(fiber);2032          invokeGuardedCallback(null, destroy, null);2033          if (hasCaughtError()) {2034            invariant(fiber !== null, 'Should be working on an effect.');2035            const error = clearCaughtError();2036            captureCommitPhaseError(fiber, error);2037          }2038          resetCurrentDebugFiberInDEV();2039        } else {2040          try {2041            destroy();2042          } catch (error) {2043            invariant(fiber !== null, 'Should be working on an effect.');2044            captureCommitPhaseError(fiber, error);2045          }2046        }2047      }2048    }2049    // Second pass: Create new passive effects.2050    let mountEffects = pendingPassiveHookEffectsMount;2051    pendingPassiveHookEffectsMount = [];2052    for (let i = 0; i < mountEffects.length; i += 2) {2053      const effect = ((mountEffects[i]: any): HookEffect);2054      const fiber = ((mountEffects[i + 1]: any): Fiber);2055      if (true) {2056        setCurrentDebugFiberInDEV(fiber);2057        invokeGuardedCallback(null, invokePassiveEffectCreate, null, effect);2058        if (hasCaughtError()) {2059          invariant(fiber !== null, 'Should be working on an effect.');2060          const error = clearCaughtError();2061          captureCommitPhaseError(fiber, error);2062        }2063        resetCurrentDebugFiberInDEV();2064      } else {2065        try {2066          const create = effect.create;2067          effect.destroy = create();2068        } catch (error) {2069          invariant(fiber !== null, 'Should be working on an effect.');2070          captureCommitPhaseError(fiber, error);2071        }2072      }2073    }2074  } else {2075    // Note: This currently assumes there are no passive effects on the root fiber2076    // because the root is not part of its own effect list.2077    // This could change in the future.2078    let effect = root.current.firstEffect;2079    while (effect !== null) {2080      if (true) {2081        setCurrentDebugFiberInDEV(effect);2082        invokeGuardedCallback(null, commitPassiveHookEffects, null, effect);2083        if (hasCaughtError()) {2084          invariant(effect !== null, 'Should be working on an effect.');2085          const error = clearCaughtError();2086          captureCommitPhaseError(effect, error);2087        }2088        resetCurrentDebugFiberInDEV();2089      } else {2090        try {2091          commitPassiveHookEffects(effect);2092        } catch (error) {2093          invariant(effect !== null, 'Should be working on an effect.');2094          captureCommitPhaseError(effect, error);2095        }2096      }2097      const nextNextEffect = effect.nextEffect;2098      // Remove nextEffect pointer to assist GC2099      effect.nextEffect = null;2100      effect = nextNextEffect;2101    }2102  }2103  if (enableSchedulerTracing) {2104    popInteractions(((prevInteractions: any): Set<Interaction>));2105    finishPendingInteractions(root, expirationTime);2106  }2107  executionContext = prevExecutionContext;2108  flushSyncCallbackQueue();2109  // If additional passive effects were scheduled, increment a counter. If this2110  // exceeds the limit, we'll fire a warning.2111  nestedPassiveUpdateCount =2112    rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2113  return true;2114}2115export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2116  return (2117    legacyErrorBoundariesThatAlreadyFailed !== null &&2118    legacyErrorBoundariesThatAlreadyFailed.has(instance)...ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js  
...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      }954    } while (true);955    resetContextDependencies();956    {957      popInteractions(prevInteractions);958    }959    popDispatcher(prevDispatcher);960    executionContext = prevExecutionContext;961    if (workInProgress !== null) {962      // Still work remaining.963      {964        markRenderYielded();965      }966      return RootIncomplete;967    } else {968      // Completed the tree.969      {970        markRenderStopped();971      } // Set this to null to indicate there's no in-progress render.972      workInProgressRoot = null;973      workInProgressRootRenderLanes = NoLanes; // Return the final exit status.974      return workInProgressRootExitStatus;975    }976  }977  /** @noinline */978  function workLoopConcurrent() {979    // Perform work until Scheduler asks us to yield980    while (workInProgress !== null && !shouldYield()) {981      performUnitOfWork(workInProgress);982    }983  }984  function performUnitOfWork(unitOfWork) {985    // The current, flushed, state of this fiber is the alternate. Ideally986    // nothing should rely on this, but relying on it here means that we don't987    // need an additional field on the work in progress.988    var current = unitOfWork.alternate;989    setCurrentFiber(unitOfWork);990    var next;991    if ( (unitOfWork.mode & ProfileMode) !== NoMode) {992      startProfilerTimer(unitOfWork);993      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);994      stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);995    } else {996      next = beginWork$1(current, unitOfWork, subtreeRenderLanes);997    }998    resetCurrentFiber();999    unitOfWork.memoizedProps = unitOfWork.pendingProps;1000    if (next === null) {1001      // If this doesn't spawn new work, complete the current work.1002      completeUnitOfWork(unitOfWork);1003    } else {1004      workInProgress = next;1005    }1006    ReactCurrentOwner$2.current = null;1007  }1008  function completeUnitOfWork(unitOfWork) {1009    // Attempt to complete the current unit of work, then move to the next1010    // sibling. If there are no more siblings, return to the parent fiber.1011    var completedWork = unitOfWork;1012    do {1013      // The current, flushed, state of this fiber is the alternate. Ideally1014      // nothing should rely on this, but relying on it here means that we don't1015      // need an additional field on the work in progress.1016      var current = completedWork.alternate;1017      var returnFiber = completedWork.return; // Check if the work completed or if something threw.1018      if ((completedWork.flags & Incomplete) === NoFlags) {1019        setCurrentFiber(completedWork);1020        var next = void 0;1021        if ( (completedWork.mode & ProfileMode) === NoMode) {1022          next = completeWork(current, completedWork, subtreeRenderLanes);1023        } else {1024          startProfilerTimer(completedWork);1025          next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.1026          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1027        }1028        resetCurrentFiber();1029        if (next !== null) {1030          // Completing this fiber spawned new work. Work on that next.1031          workInProgress = next;1032          return;1033        }1034        resetChildLanes(completedWork);1035        if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete1036        (returnFiber.flags & Incomplete) === NoFlags) {1037          // Append all the effects of the subtree and this fiber onto the effect1038          // list of the parent. The completion order of the children affects the1039          // side-effect order.1040          if (returnFiber.firstEffect === null) {1041            returnFiber.firstEffect = completedWork.firstEffect;1042          }1043          if (completedWork.lastEffect !== null) {1044            if (returnFiber.lastEffect !== null) {1045              returnFiber.lastEffect.nextEffect = completedWork.firstEffect;1046            }1047            returnFiber.lastEffect = completedWork.lastEffect;1048          } // If this fiber had side-effects, we append it AFTER the children's1049          // side-effects. We can perform certain side-effects earlier if needed,1050          // by doing multiple passes over the effect list. We don't want to1051          // schedule our own side-effect on our own list because if end up1052          // reusing children we'll schedule this effect onto itself since we're1053          // at the end.1054          var flags = completedWork.flags; // Skip both NoWork and PerformedWork tags when creating the effect1055          // list. PerformedWork effect is read by React DevTools but shouldn't be1056          // committed.1057          if (flags > PerformedWork) {1058            if (returnFiber.lastEffect !== null) {1059              returnFiber.lastEffect.nextEffect = completedWork;1060            } else {1061              returnFiber.firstEffect = completedWork;1062            }1063            returnFiber.lastEffect = completedWork;1064          }1065        }1066      } else {1067        // This fiber did not complete because something threw. Pop values off1068        // the stack without entering the complete phase. If this is a boundary,1069        // capture values if possible.1070        var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.1071        if (_next !== null) {1072          // If completing this work spawned new work, do that next. We'll come1073          // back here again.1074          // Since we're restarting, remove anything that is not a host effect1075          // from the effect tag.1076          _next.flags &= HostEffectMask;1077          workInProgress = _next;1078          return;1079        }1080        if ( (completedWork.mode & ProfileMode) !== NoMode) {1081          // Record the render duration for the fiber that errored.1082          stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.1083          var actualDuration = completedWork.actualDuration;1084          var child = completedWork.child;1085          while (child !== null) {1086            actualDuration += child.actualDuration;1087            child = child.sibling;1088          }1089          completedWork.actualDuration = actualDuration;1090        }1091        if (returnFiber !== null) {1092          // Mark the parent fiber as incomplete and clear its effect list.1093          returnFiber.firstEffect = returnFiber.lastEffect = null;1094          returnFiber.flags |= Incomplete;1095        }1096      }1097      var siblingFiber = completedWork.sibling;1098      if (siblingFiber !== null) {1099        // If there is more work to do in this returnFiber, do that next.1100        workInProgress = siblingFiber;1101        return;1102      } // Otherwise, return to the parent1103      completedWork = returnFiber; // Update the next thing we're working on in case something throws.1104      workInProgress = completedWork;1105    } while (completedWork !== null); // We've reached the root.1106    if (workInProgressRootExitStatus === RootIncomplete) {1107      workInProgressRootExitStatus = RootCompleted;1108    }1109  }1110  function resetChildLanes(completedWork) {1111    if ( // TODO: Move this check out of the hot path by moving `resetChildLanes`1112    // to switch statement in `completeWork`.1113    (completedWork.tag === LegacyHiddenComponent || completedWork.tag === OffscreenComponent) && completedWork.memoizedState !== null && !includesSomeLane(subtreeRenderLanes, OffscreenLane) && (completedWork.mode & ConcurrentMode) !== NoLanes) {1114      // The children of this component are hidden. Don't bubble their1115      // expiration times.1116      return;1117    }1118    var newChildLanes = NoLanes; // Bubble up the earliest expiration time.1119    if ( (completedWork.mode & ProfileMode) !== NoMode) {1120      // In profiling mode, resetChildExpirationTime is also used to reset1121      // profiler durations.1122      var actualDuration = completedWork.actualDuration;1123      var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will1124      // only be updated if work is done on the fiber (i.e. it doesn't bailout).1125      // When work is done, it should bubble to the parent's actualDuration. If1126      // the fiber has not been cloned though, (meaning no work was done), then1127      // this value will reflect the amount of time spent working on a previous1128      // render. In that case it should not bubble. We determine whether it was1129      // cloned by comparing the child pointer.1130      var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child;1131      var child = completedWork.child;1132      while (child !== null) {1133        newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));1134        if (shouldBubbleActualDurations) {1135          actualDuration += child.actualDuration;1136        }1137        treeBaseDuration += child.treeBaseDuration;1138        child = child.sibling;1139      }1140      var isTimedOutSuspense = completedWork.tag === SuspenseComponent && completedWork.memoizedState !== null;1141      if (isTimedOutSuspense) {1142        // Don't count time spent in a timed out Suspense subtree as part of the base duration.1143        var primaryChildFragment = completedWork.child;1144        if (primaryChildFragment !== null) {1145          treeBaseDuration -= primaryChildFragment.treeBaseDuration;1146        }1147      }1148      completedWork.actualDuration = actualDuration;1149      completedWork.treeBaseDuration = treeBaseDuration;1150    } else {1151      var _child = completedWork.child;1152      while (_child !== null) {1153        newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));1154        _child = _child.sibling;1155      }1156    }1157    completedWork.childLanes = newChildLanes;1158  }1159  function commitRoot(root) {1160    var renderPriorityLevel = getCurrentPriorityLevel();1161    runWithPriority$1(ImmediatePriority$1, commitRootImpl.bind(null, root, renderPriorityLevel));1162    return null;1163  }1164  function commitRootImpl(root, renderPriorityLevel) {1165    do {1166      // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1167      // means `flushPassiveEffects` will sometimes result in additional1168      // passive effects. So we need to keep flushing in a loop until there are1169      // no more pending effects.1170      // TODO: Might be better if `flushPassiveEffects` did not automatically1171      // flush synchronous work at the end, to avoid factoring hazards like this.1172      flushPassiveEffects();1173    } while (rootWithPendingPassiveEffects !== null);1174    flushRenderPhaseStrictModeWarningsInDEV();1175    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1176      {1177        throw Error( "Should not already be working." );1178      }1179    }1180    var finishedWork = root.finishedWork;1181    var lanes = root.finishedLanes;1182    {1183      markCommitStarted(lanes);1184    }1185    if (finishedWork === null) {1186      {1187        markCommitStopped();1188      }1189      return null;1190    }1191    root.finishedWork = null;1192    root.finishedLanes = NoLanes;1193    if (!(finishedWork !== root.current)) {1194      {1195        throw Error( "Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue." );1196      }1197    } // commitRoot never returns a continuation; it always finishes synchronously.1198    // So we can clear these now to allow a new callback to be scheduled.1199    root.callbackNode = null; // Update the first and last pending times on this root. The new first1200    // pending time is whatever is left on the root fiber.1201    var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1202    markRootFinished(root, remainingLanes); // Clear already finished discrete updates in case that a later call of1203    // `flushDiscreteUpdates` starts a useless render pass which may cancels1204    // a scheduled timeout.1205    if (rootsWithPendingDiscreteUpdates !== null) {1206      if (!hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root)) {1207        rootsWithPendingDiscreteUpdates.delete(root);1208      }1209    }1210    if (root === workInProgressRoot) {1211      // We can reset these now that they are finished.1212      workInProgressRoot = null;1213      workInProgress = null;1214      workInProgressRootRenderLanes = NoLanes;1215    } // Get the list of effects.1216    var firstEffect;1217    if (finishedWork.flags > PerformedWork) {1218      // A fiber's effect list consists only of its children, not itself. So if1219      // the root has an effect, we need to add it to the end of the list. The1220      // resulting list is the set that would belong to the root's parent, if it1221      // had one; that is, all the effects in the tree including the root.1222      if (finishedWork.lastEffect !== null) {1223        finishedWork.lastEffect.nextEffect = finishedWork;1224        firstEffect = finishedWork.firstEffect;1225      } else {1226        firstEffect = finishedWork;1227      }1228    } else {1229      // There is no effect on the root.1230      firstEffect = finishedWork.firstEffect;1231    }1232    if (firstEffect !== null) {1233      var prevExecutionContext = executionContext;1234      executionContext |= CommitContext;1235      var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles1236      ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass1237      // of the effect list for each phase: all mutation effects come before all1238      // layout effects, and so on.1239      // The first phase a "before mutation" phase. We use this phase to read the1240      // state of the host tree right before we mutate it. This is where1241      // getSnapshotBeforeUpdate is called.1242      focusedInstanceHandle = prepareForCommit(root.containerInfo);1243      shouldFireAfterActiveInstanceBlur = false;1244      nextEffect = firstEffect;1245      do {1246        {1247          invokeGuardedCallback(null, commitBeforeMutationEffects, null);1248          if (hasCaughtError()) {1249            if (!(nextEffect !== null)) {1250              {1251                throw Error( "Should be working on an effect." );1252              }1253            }1254            var error = clearCaughtError();1255            captureCommitPhaseError(nextEffect, error);1256            nextEffect = nextEffect.nextEffect;1257          }1258        }1259      } while (nextEffect !== null); // We no longer need to track the active instance fiber1260      focusedInstanceHandle = null;1261      {1262        // Mark the current commit time to be shared by all Profilers in this1263        // batch. This enables them to be grouped later.1264        recordCommitTime();1265      } // The next phase is the mutation phase, where we mutate the host tree.1266      nextEffect = firstEffect;1267      do {1268        {1269          invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel);1270          if (hasCaughtError()) {1271            if (!(nextEffect !== null)) {1272              {1273                throw Error( "Should be working on an effect." );1274              }1275            }1276            var _error = clearCaughtError();1277            captureCommitPhaseError(nextEffect, _error);1278            nextEffect = nextEffect.nextEffect;1279          }1280        }1281      } while (nextEffect !== null);1282      resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after1283      // the mutation phase, so that the previous tree is still current during1284      // componentWillUnmount, but before the layout phase, so that the finished1285      // work is current during componentDidMount/Update.1286      root.current = finishedWork; // The next phase is the layout phase, where we call effects that read1287      // the host tree after it's been mutated. The idiomatic use case for this is1288      // layout, but class component lifecycles also fire here for legacy reasons.1289      nextEffect = firstEffect;1290      do {1291        {1292          invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);1293          if (hasCaughtError()) {1294            if (!(nextEffect !== null)) {1295              {1296                throw Error( "Should be working on an effect." );1297              }1298            }1299            var _error2 = clearCaughtError();1300            captureCommitPhaseError(nextEffect, _error2);1301            nextEffect = nextEffect.nextEffect;1302          }1303        }1304      } while (nextEffect !== null);1305      nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an1306      // opportunity to paint.1307      requestPaint();1308      {1309        popInteractions(prevInteractions);1310      }1311      executionContext = prevExecutionContext;1312    } else {1313      // No effects.1314      root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were1315      // no effects.1316      // TODO: Maybe there's a better way to report this.1317      {1318        recordCommitTime();1319      }1320    }1321    var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1322    if (rootDoesHavePassiveEffects) {1323      // This commit has passive effects. Stash a reference to them. But don't1324      // schedule a callback until after flushing layout work.1325      rootDoesHavePassiveEffects = false;1326      rootWithPendingPassiveEffects = root;1327      pendingPassiveEffectsLanes = lanes;1328      pendingPassiveEffectsRenderPriority = renderPriorityLevel;1329    } else {1330      // We are done with the effect chain at this point so let's clear the1331      // nextEffect pointers to assist with GC. If we have passive effects, we'll1332      // clear this in flushPassiveEffects.1333      nextEffect = firstEffect;1334      while (nextEffect !== null) {1335        var nextNextEffect = nextEffect.nextEffect;1336        nextEffect.nextEffect = null;1337        if (nextEffect.flags & Deletion) {1338          detachFiberAfterEffects(nextEffect);1339        }1340        nextEffect = nextNextEffect;1341      }1342    } // Read this again, since an effect might have updated it1343    remainingLanes = root.pendingLanes; // Check if there's remaining work on this root1344    if (remainingLanes !== NoLanes) {1345      {1346        if (spawnedWorkDuringRender !== null) {1347          var expirationTimes = spawnedWorkDuringRender;1348          spawnedWorkDuringRender = null;1349          for (var i = 0; i < expirationTimes.length; i++) {1350            scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);1351          }1352        }1353        schedulePendingInteractions(root, remainingLanes);1354      }1355    } else {1356      // If there's no remaining work, we can clear the set of already failed1357      // error boundaries.1358      legacyErrorBoundariesThatAlreadyFailed = null;1359    }1360    {1361      if (!rootDidHavePassiveEffects) {1362        // If there are no passive effects, then we can complete the pending interactions.1363        // Otherwise, we'll wait until after the passive effects are flushed.1364        // Wait to do this until after remaining work has been scheduled,1365        // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1366        finishPendingInteractions(root, lanes);1367      }1368    }1369    if (remainingLanes === SyncLane) {1370      // Count the number of times the root synchronously re-renders without1371      // finishing. If there are too many, it indicates an infinite update loop.1372      if (root === rootWithNestedUpdates) {1373        nestedUpdateCount++;1374      } else {1375        nestedUpdateCount = 0;1376        rootWithNestedUpdates = root;1377      }1378    } else {1379      nestedUpdateCount = 0;1380    }1381    onCommitRoot(finishedWork.stateNode, renderPriorityLevel);1382    {1383      onCommitRoot$1();1384    } // Always call this before exiting `commitRoot`, to ensure that any1385    // additional work on this root is scheduled.1386    ensureRootIsScheduled(root, now());1387    if (hasUncaughtError) {1388      hasUncaughtError = false;1389      var _error3 = firstUncaughtError;1390      firstUncaughtError = null;1391      throw _error3;1392    }1393    if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1394      {1395        markCommitStopped();1396      } // This is a legacy edge case. We just committed the initial mount of1397      // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1398      // synchronously, but layout updates should be deferred until the end1399      // of the batch.1400      return null;1401    } // If layout work was scheduled, flush it now.1402    flushSyncCallbackQueue();1403    {1404      markCommitStopped();1405    }1406    return null;1407  }1408  function commitBeforeMutationEffects() {1409    while (nextEffect !== null) {1410      var current = nextEffect.alternate;1411      if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1412        if ((nextEffect.flags & Deletion) !== NoFlags) {1413          if (doesFiberContain(nextEffect, focusedInstanceHandle)) {1414            shouldFireAfterActiveInstanceBlur = true;1415          }1416        } else {1417          // TODO: Move this out of the hot path using a dedicated effect tag.1418          if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {1419            shouldFireAfterActiveInstanceBlur = true;1420          }1421        }1422      }1423      var flags = nextEffect.flags;1424      if ((flags & Snapshot) !== NoFlags) {1425        setCurrentFiber(nextEffect);1426        commitBeforeMutationLifeCycles(current, nextEffect);1427        resetCurrentFiber();1428      }1429      if ((flags & Passive) !== NoFlags) {1430        // If there are passive effects, schedule a callback to flush at1431        // the earliest opportunity.1432        if (!rootDoesHavePassiveEffects) {1433          rootDoesHavePassiveEffects = true;1434          scheduleCallback(NormalPriority$1, function () {1435            flushPassiveEffects();1436            return null;1437          });1438        }1439      }1440      nextEffect = nextEffect.nextEffect;1441    }1442  }1443  function commitMutationEffects(root, renderPriorityLevel) {1444    // TODO: Should probably move the bulk of this function to commitWork.1445    while (nextEffect !== null) {1446      setCurrentFiber(nextEffect);1447      var flags = nextEffect.flags;1448      if (flags & ContentReset) {1449        commitResetTextContent(nextEffect);1450      }1451      if (flags & Ref) {1452        var current = nextEffect.alternate;1453        if (current !== null) {1454          commitDetachRef(current);1455        }1456      } // The following switch statement is only concerned about placement,1457      // updates, and deletions. To avoid needing to add a case for every possible1458      // bitmap value, we remove the secondary effects from the effect tag and1459      // switch on that value.1460      var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);1461      switch (primaryFlags) {1462        case Placement:1463          {1464            commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1465            // inserted, before any life-cycles like componentDidMount gets called.1466            // TODO: findDOMNode doesn't rely on this any more but isMounted does1467            // and isMounted is deprecated anyway so we should be able to kill this.1468            nextEffect.flags &= ~Placement;1469            break;1470          }1471        case PlacementAndUpdate:1472          {1473            // Placement1474            commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1475            // inserted, before any life-cycles like componentDidMount gets called.1476            nextEffect.flags &= ~Placement; // Update1477            var _current = nextEffect.alternate;1478            commitWork(_current, nextEffect);1479            break;1480          }1481        case Hydrating:1482          {1483            nextEffect.flags &= ~Hydrating;1484            break;1485          }1486        case HydratingAndUpdate:1487          {1488            nextEffect.flags &= ~Hydrating; // Update1489            var _current2 = nextEffect.alternate;1490            commitWork(_current2, nextEffect);1491            break;1492          }1493        case Update:1494          {1495            var _current3 = nextEffect.alternate;1496            commitWork(_current3, nextEffect);1497            break;1498          }1499        case Deletion:1500          {1501            commitDeletion(root, nextEffect);1502            break;1503          }1504      }1505      resetCurrentFiber();1506      nextEffect = nextEffect.nextEffect;1507    }1508  }1509  function commitLayoutEffects(root, committedLanes) {1510    {1511      markLayoutEffectsStarted(committedLanes);1512    } // TODO: Should probably move the bulk of this function to commitWork.1513    while (nextEffect !== null) {1514      setCurrentFiber(nextEffect);1515      var flags = nextEffect.flags;1516      if (flags & (Update | Callback)) {1517        var current = nextEffect.alternate;1518        commitLifeCycles(root, current, nextEffect);1519      }1520      {1521        if (flags & Ref) {1522          commitAttachRef(nextEffect);1523        }1524      }1525      resetCurrentFiber();1526      nextEffect = nextEffect.nextEffect;1527    }1528    {1529      markLayoutEffectsStopped();1530    }1531  }1532  function flushPassiveEffects() {1533    // Returns whether passive effects were flushed.1534    if (pendingPassiveEffectsRenderPriority !== NoPriority$1) {1535      var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority$1 ? NormalPriority$1 : pendingPassiveEffectsRenderPriority;1536      pendingPassiveEffectsRenderPriority = NoPriority$1;1537      {1538        return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);1539      }1540    }1541    return false;1542  }1543  function enqueuePendingPassiveHookEffectMount(fiber, effect) {1544    pendingPassiveHookEffectsMount.push(effect, fiber);1545    if (!rootDoesHavePassiveEffects) {1546      rootDoesHavePassiveEffects = true;1547      scheduleCallback(NormalPriority$1, function () {1548        flushPassiveEffects();1549        return null;1550      });1551    }1552  }1553  function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {1554    pendingPassiveHookEffectsUnmount.push(effect, fiber);1555    {1556      fiber.flags |= PassiveUnmountPendingDev;1557      var alternate = fiber.alternate;1558      if (alternate !== null) {1559        alternate.flags |= PassiveUnmountPendingDev;1560      }1561    }1562    if (!rootDoesHavePassiveEffects) {1563      rootDoesHavePassiveEffects = true;1564      scheduleCallback(NormalPriority$1, function () {1565        flushPassiveEffects();1566        return null;1567      });1568    }1569  }1570  function invokePassiveEffectCreate(effect) {1571    var create = effect.create;1572    effect.destroy = create();1573  }1574  function flushPassiveEffectsImpl() {1575    if (rootWithPendingPassiveEffects === null) {1576      return false;1577    }1578    var root = rootWithPendingPassiveEffects;1579    var lanes = pendingPassiveEffectsLanes;1580    rootWithPendingPassiveEffects = null;1581    pendingPassiveEffectsLanes = NoLanes;1582    if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1583      {1584        throw Error( "Cannot flush passive effects while already rendering." );1585      }1586    }1587    {1588      markPassiveEffectsStarted(lanes);1589    }1590    {1591      isFlushingPassiveEffects = true;1592    }1593    var prevExecutionContext = executionContext;1594    executionContext |= CommitContext;1595    var prevInteractions = pushInteractions(root); // It's important that ALL pending passive effect destroy functions are called1596    // before ANY passive effect create functions are called.1597    // Otherwise effects in sibling components might interfere with each other.1598    // e.g. a destroy function in one component may unintentionally override a ref1599    // value set by a create function in another component.1600    // Layout effects have the same constraint.1601    // First pass: Destroy stale passive effects.1602    var unmountEffects = pendingPassiveHookEffectsUnmount;1603    pendingPassiveHookEffectsUnmount = [];1604    for (var i = 0; i < unmountEffects.length; i += 2) {1605      var _effect = unmountEffects[i];1606      var fiber = unmountEffects[i + 1];1607      var destroy = _effect.destroy;1608      _effect.destroy = undefined;1609      {1610        fiber.flags &= ~PassiveUnmountPendingDev;1611        var alternate = fiber.alternate;1612        if (alternate !== null) {1613          alternate.flags &= ~PassiveUnmountPendingDev;1614        }1615      }1616      if (typeof destroy === 'function') {1617        {1618          setCurrentFiber(fiber);1619          {1620            invokeGuardedCallback(null, destroy, null);1621          }1622          if (hasCaughtError()) {1623            if (!(fiber !== null)) {1624              {1625                throw Error( "Should be working on an effect." );1626              }1627            }1628            var error = clearCaughtError();1629            captureCommitPhaseError(fiber, error);1630          }1631          resetCurrentFiber();1632        }1633      }1634    } // Second pass: Create new passive effects.1635    var mountEffects = pendingPassiveHookEffectsMount;1636    pendingPassiveHookEffectsMount = [];1637    for (var _i = 0; _i < mountEffects.length; _i += 2) {1638      var _effect2 = mountEffects[_i];1639      var _fiber = mountEffects[_i + 1];1640      {1641        setCurrentFiber(_fiber);1642        {1643          invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);1644        }1645        if (hasCaughtError()) {1646          if (!(_fiber !== null)) {1647            {1648              throw Error( "Should be working on an effect." );1649            }1650          }1651          var _error4 = clearCaughtError();1652          captureCommitPhaseError(_fiber, _error4);1653        }1654        resetCurrentFiber();1655      }1656    } // Note: This currently assumes there are no passive effects on the root fiber1657    // because the root is not part of its own effect list.1658    // This could change in the future.1659    var effect = root.current.firstEffect;1660    while (effect !== null) {1661      var nextNextEffect = effect.nextEffect; // Remove nextEffect pointer to assist GC1662      effect.nextEffect = null;1663      if (effect.flags & Deletion) {1664        detachFiberAfterEffects(effect);1665      }1666      effect = nextNextEffect;1667    }1668    {1669      popInteractions(prevInteractions);1670      finishPendingInteractions(root, lanes);1671    }1672    {1673      isFlushingPassiveEffects = false;1674    }1675    {1676      markPassiveEffectsStopped();1677    }1678    executionContext = prevExecutionContext;1679    flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this1680    // exceeds the limit, we'll fire a warning.1681    nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;1682    return true;1683  }...4 - commitWork.js
Source:4 - commitWork.js  
...151    // Tell Scheduler to yield at the end of the frame, so the browser has an152    // opportunity to paint.153    requestPaint();154    if (enableSchedulerTracing) {155      popInteractions(((prevInteractions: any): Set<Interaction>));156    }157    executionContext = prevExecutionContext;158    // Reset the priority to the previous non-sync value.159    setCurrentUpdatePriority(previousPriority);160    ReactCurrentBatchConfig.transition = prevTransition;161  } else {162    // No effects.163    root.current = finishedWork;164    // Measure these anyway so the flamegraph explicitly shows that there were165    // no effects.166    // TODO: Maybe there's a better way to report this.167    if (enableProfilerTimer) {168      recordCommitTime();169    }170  }171  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;172  if (rootDoesHavePassiveEffects) {173    // This commit has passive effects. Stash a reference to them. But don't174    // schedule a callback until after flushing layout work.175    rootDoesHavePassiveEffects = false;176    rootWithPendingPassiveEffects = root;177    pendingPassiveEffectsLanes = lanes;178  }179  // Read this again, since an effect might have updated it180  remainingLanes = root.pendingLanes;181  // Check if there's remaining work on this root182  if (remainingLanes !== NoLanes) {183    if (enableSchedulerTracing) {184      if (spawnedWorkDuringRender !== null) {185        const expirationTimes = spawnedWorkDuringRender;186        spawnedWorkDuringRender = null;187        for (let i = 0; i < expirationTimes.length; i++) {188          scheduleInteractions(189            root,190            expirationTimes[i],191            root.memoizedInteractions,192          );193        }194      }195      schedulePendingInteractions(root, remainingLanes);196    }197  } else {198    // If there's no remaining work, we can clear the set of already failed199    // error boundaries.200    legacyErrorBoundariesThatAlreadyFailed = null;201  }202  if (enableSchedulerTracing) {203    if (!rootDidHavePassiveEffects) {204      // If there are no passive effects, then we can complete the pending interactions.205      // Otherwise, we'll wait until after the passive effects are flushed.206      // Wait to do this until after remaining work has been scheduled,207      // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.208      finishPendingInteractions(root, lanes);209    }210  }211  if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {212    if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {213      markNestedUpdateScheduled();214    }215    // Count the number of times the root synchronously re-renders without216    // finishing. If there are too many, it indicates an infinite update loop.217    if (root === rootWithNestedUpdates) {218      nestedUpdateCount++;219    } else {220      nestedUpdateCount = 0;221      rootWithNestedUpdates = root;222    }223  } else {224    nestedUpdateCount = 0;225  }226  onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);227  // Always call this before exiting `commitRoot`, to ensure that any228  // additional work on this root is scheduled.229  ensureRootIsScheduled(root, now());230  if (hasUncaughtError) {231    hasUncaughtError = false;232    const error = firstUncaughtError;233    firstUncaughtError = null;234    throw error;235  }236  if ((executionContext & LegacyUnbatchedContext) !== NoContext) {237    if (enableSchedulingProfiler) {238      markCommitStopped();239    }240    // This is a legacy edge case. We just committed the initial mount of241    // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired242    // synchronously, but layout updates should be deferred until the end243    // of the batch.244    return null;245  }246  // If the passive effects are the result of a discrete render, flush them247  // synchronously at the end of the current task so that the result is248  // immediately observable. Otherwise, we assume that they are not249  // order-dependent and do not need to be observed by external systems, so we250  // can wait until after paint.251  // TODO: We can optimize this by not scheduling the callback earlier. Since we252  // currently schedule the callback in multiple places, will wait until those253  // are consolidated.254  if (255    includesSomeLane(pendingPassiveEffectsLanes, SyncLane) &&256    root.tag !== LegacyRoot257  ) {258    flushPassiveEffects();259  }260  // If layout work was scheduled, flush it now.261  flushSyncCallbackQueue();262  if (enableSchedulingProfiler) {263    markCommitStopped();264  }265  return null;266}267export function flushPassiveEffects(): boolean {268  // Returns whether passive effects were flushed.269  if (pendingPassiveEffectsLanes !== NoLanes) {270    const priority = higherEventPriority(271      DefaultEventPriority,272      lanesToEventPriority(pendingPassiveEffectsLanes),273    );274    const prevTransition = ReactCurrentBatchConfig.transition;275    const previousPriority = getCurrentUpdatePriority();276    try {277      ReactCurrentBatchConfig.transition = 0;278      setCurrentUpdatePriority(priority);279      return flushPassiveEffectsImpl();280    } finally {281      setCurrentUpdatePriority(previousPriority);282      ReactCurrentBatchConfig.transition = prevTransition;283    }284  }285  return false;286}287function flushPassiveEffectsImpl() {288  if (rootWithPendingPassiveEffects === null) {289    return false;290  }291  const root = rootWithPendingPassiveEffects;292  const lanes = pendingPassiveEffectsLanes;293  rootWithPendingPassiveEffects = null;294  pendingPassiveEffectsLanes = NoLanes;295  invariant(296    (executionContext & (RenderContext | CommitContext)) === NoContext,297    'Cannot flush passive effects while already rendering.',298  );299  if (enableSchedulingProfiler) {300    markPassiveEffectsStarted(lanes);301  }302  const prevExecutionContext = executionContext;303  executionContext |= CommitContext;304  const prevInteractions = pushInteractions(root);305  commitPassiveUnmountEffects(root.current);306  commitPassiveMountEffects(root, root.current);307  // TODO: Move to commitPassiveMountEffects308  if (enableProfilerTimer && enableProfilerCommitHooks) {309    const profilerEffects = pendingPassiveProfilerEffects;310    pendingPassiveProfilerEffects = [];311    for (let i = 0; i < profilerEffects.length; i++) {312      const fiber = ((profilerEffects[i]: any): Fiber);313      commitPassiveEffectDurations(root, fiber);314    }315  }316  if (enableSchedulerTracing) {317    popInteractions(((prevInteractions: any): Set<Interaction>));318    finishPendingInteractions(root, lanes);319  }320  if (enableSchedulingProfiler) {321    markPassiveEffectsStopped();322  }323  executionContext = prevExecutionContext;324  flushSyncCallbackQueue();325  // If additional passive effects were scheduled, increment a counter. If this326  // exceeds the limit, we'll fire a warning.327  nestedPassiveUpdateCount =328    rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;329  return true;...commitRootImpl.js
Source:commitRootImpl.js  
...142        nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an143        // opportunity to paint.144        requestPaint();145        if (enableSchedulerTracing) {146            popInteractions(prevInteractions);147        }148        executionContext = prevExecutionContext;149    } else {150        // No effects.151        root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were152        // no effects.153        // TODO: Maybe there's a better way to report this.154        startCommitSnapshotEffectsTimer();155        stopCommitSnapshotEffectsTimer();156        if (enableProfilerTimer) {157            recordCommitTime();158        }159        startCommitHostEffectsTimer();160        stopCommitHostEffectsTimer();...finishSyncRender.js
Source:finishSyncRender.js  
...129        // Tell Scheduler to yield at the end of the frame, so the browser has an130        // opportunity to paint.131        requestPaint();132        if (enableSchedulerTracing) {133            popInteractions(((prevInteractions: any): Set < Interaction > ));134        }135        executionContext = prevExecutionContext;136    } else {137        // No effects.138        root.current = finishedWork;139        // Measure these anyway so the flamegraph explicitly shows that there were140        // no effects.141        // TODO: Maybe there's a better way to report this.142        startCommitSnapshotEffectsTimer();143        stopCommitSnapshotEffectsTimer();144        if (enableProfilerTimer) {145            recordCommitTime();146        }147        startCommitHostEffectsTimer();...flushPassiveEffectsImpl.js
Source:flushPassiveEffectsImpl.js  
...40        effect.nextEffect = null;41        effect = nextNextEffect;42    }43    if (enableSchedulerTracing) {44        popInteractions(prevInteractions);45        finishPendingInteractions(root, expirationTime);46    }47    executionContext = prevExecutionContext;48    flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this49    // exceeds the limit, we'll fire a warning.50    nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;51    return true;...Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3    const browser = await chromium.launch();4    const context = await browser.newContext();5    const page = await context.newPage();6    await page.click('text=Get started');7    await page.waitForSelector('text=API reference');8    await page.click('text=API reference');9    await page.waitForSelector('text=class Playwright');10    await page.click('text=class Playwright');11    await page.waitForSelector('text=launch');12    await page.click('text=launch');13    await page.waitForSelector('text=launchPersistentContext');14    await page.click('text=launchPersistentContext');15    await page.waitForSelector('text=launchServer');16    await page.click('text=launchServer');17    await page.waitForSelector('text=launchPersistentServer');18    await page.click('text=launchPersistentServer');19    await page.waitForSelector('text=launchBrowserServer');20    await page.click('text=launchBrowserServer');21    await page.waitForSelector('text=connectOverCDP');22    await page.click('text=connectOverCDP');23    await page.waitForSelector('text=connect');24    await page.click('text=connect');25    await page.waitForSelector('text=selectors');26    await page.click('text=selectors');27    await page.waitForSelector('text=Chromium');28    await page.click('text=Chromium');29    await page.waitForSelector('text=Firefox');30    await page.click('text=Firefox');31    await page.waitForSelector('text=WebKit');32    await page.click('text=WebKit');33    await page.waitForSelector('text=class Browser');34    await page.click('text=class Browser');35    await page.waitForSelector('text=class BrowserContext');36    await page.click('text=class BrowserContext');37    await page.waitForSelector('text=class BrowserServer');38    await page.click('text=class BrowserServer');39    await page.waitForSelector('text=class BrowserType');40    await page.click('text=class BrowserType');41    await page.waitForSelector('text=class CDPSession');42    await page.click('text=class CDPSession');43    await page.waitForSelector('text=class ConsoleMessage');44    await page.click('text=class ConsoleMessage');45    await page.waitForSelector('text=class Dialog');46    await page.click('text=class Dialog');Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3  const browser = await chromium.launch();4  const page = await browser.newPage();5  await page.click('text=Get started');6  await page.click('text=Docs');7  await page.click('text=API');Using AI Code Generation
1const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');2const interactions = popInteractions();3const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');4const interactions = popInteractions();5const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');6const interactions = popInteractions();7const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');8const interactions = popInteractions();9const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');10const interactions = popInteractions();11const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');12const interactions = popInteractions();13const { popInteractions } = require('@playwright/test/lib/server/trace/recorder');14const interactions = popInteractions();Using AI Code Generation
1const { popInteractions } = require('playwright-core/lib/server/trace/recorder');2const interactions = popInteractions();3console.log(interactions);4  {5    "action": {6    },7  },8  {9    "action": {10    },11  },12  {13    "action": {14    },15  },16  {17    "action": {18    },19  },20  {21    "action": {22    },23  }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!!
