Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js  
...1322  // 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)2119  );2120}2121export function markLegacyErrorBoundaryAsFailed(instance: mixed) {2122  if (legacyErrorBoundariesThatAlreadyFailed === null) {2123    legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);2124  } else {2125    legacyErrorBoundariesThatAlreadyFailed.add(instance);2126  }2127}2128function prepareToThrowUncaughtError(error: mixed) {2129  if (!hasUncaughtError) {2130    hasUncaughtError = true;2131    firstUncaughtError = error;2132  }2133}2134export const onUncaughtError = prepareToThrowUncaughtError;2135function captureCommitPhaseErrorOnRoot(2136  rootFiber: Fiber,2137  sourceFiber: Fiber,2138  error: mixed,2139) {2140  const errorInfo = createCapturedValue(error, sourceFiber);2141  const update = createRootErrorUpdate(rootFiber, errorInfo, Sync);2142  enqueueUpdate(rootFiber, update);2143  const root = markUpdateTimeFromFiberToRoot(rootFiber, Sync);2144  if (root !== null) {2145    ensureRootIsScheduled(root);2146    schedulePendingInteractions(root, Sync);2147  }2148}2149export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {2150  if (sourceFiber.tag === HostRoot) {2151    // Error was thrown at the root. There is no parent, so the root2152    // itself should capture it.2153    captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);2154    return;2155  }2156  let fiber = sourceFiber.return;2157  while (fiber !== null) {2158    if (fiber.tag === HostRoot) {2159      captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);2160      return;2161    } else if (fiber.tag === ClassComponent) {2162      const ctor = fiber.type;2163      const instance = fiber.stateNode;2164      if (2165        typeof ctor.getDerivedStateFromError === 'function' ||2166        (typeof instance.componentDidCatch === 'function' &&2167          !isAlreadyFailedLegacyErrorBoundary(instance))2168      ) {2169        const errorInfo = createCapturedValue(error, sourceFiber);2170        const update = createClassErrorUpdate(2171          fiber,2172          errorInfo,2173          // TODO: This is always sync2174          Sync,2175        );2176        enqueueUpdate(fiber, update);2177        const root = markUpdateTimeFromFiberToRoot(fiber, Sync);2178        if (root !== null) {2179          ensureRootIsScheduled(root);2180          schedulePendingInteractions(root, Sync);2181        }2182        return;2183      }2184    }2185    fiber = fiber.return;2186  }2187}2188export function pingSuspendedRoot(2189  root: FiberRoot,2190  thenable: Thenable,2191  suspendedTime: ExpirationTime,2192) {2193  const pingCache = root.pingCache;2194  if (pingCache !== null) {2195    // The thenable resolved, so we no longer need to memoize, because it will2196    // never be thrown again.2197    pingCache.delete(thenable);2198  }2199  if (workInProgressRoot === root && renderExpirationTime === suspendedTime) {2200    // Received a ping at the same priority level at which we're currently2201    // rendering. We might want to restart this render. This should mirror2202    // the logic of whether or not a root suspends once it completes.2203    // TODO: If we're rendering sync either due to Sync, Batched or expired,2204    // we should probably never restart.2205    // If we're suspended with delay, we'll always suspend so we can always2206    // restart. If we're suspended without any updates, it might be a retry.2207    // If it's early in the retry we can restart. We can't know for sure2208    // whether we'll eventually process an update during this render pass,2209    // but it's somewhat unlikely that we get to a ping before that, since2210    // getting to the root most update is usually very fast.2211    if (2212      workInProgressRootExitStatus === RootSuspendedWithDelay ||2213      (workInProgressRootExitStatus === RootSuspended &&2214        workInProgressRootLatestProcessedExpirationTime === Sync &&2215        now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)2216    ) {2217      // Restart from the root. Don't need to schedule a ping because2218      // we're already working on this tree.2219      prepareFreshStack(root, renderExpirationTime);2220    } else {2221      // Even though we can't restart right now, we might get an2222      // opportunity later. So we mark this render as having a ping.2223      workInProgressRootHasPendingPing = true;2224    }2225    return;2226  }2227  if (!isRootSuspendedAtTime(root, suspendedTime)) {2228    // The root is no longer suspended at this time.2229    return;2230  }2231  const lastPingedTime = root.lastPingedTime;2232  if (lastPingedTime !== NoWork && lastPingedTime < suspendedTime) {2233    // There's already a lower priority ping scheduled.2234    return;2235  }2236  // Mark the time at which this ping was scheduled.2237  root.lastPingedTime = suspendedTime;2238  if (!enableTrainModelFix && root.finishedExpirationTime === suspendedTime) {2239    // If there's a pending fallback waiting to commit, throw it away.2240    root.finishedExpirationTime = NoWork;2241    root.finishedWork = null;2242  }2243  ensureRootIsScheduled(root);2244  schedulePendingInteractions(root, suspendedTime);2245}2246function retryTimedOutBoundary(2247  boundaryFiber: Fiber,2248  retryTime: ExpirationTime,2249) {2250  // The boundary fiber (a Suspense component or SuspenseList component)2251  // previously was rendered in its fallback state. One of the promises that2252  // suspended it has resolved, which means at least part of the tree was2253  // likely unblocked. Try rendering again, at a new expiration time.2254  if (retryTime === NoWork) {2255    const suspenseConfig = null; // Retries don't carry over the already committed update.2256    const currentTime = requestCurrentTimeForUpdate();2257    retryTime = computeExpirationForFiber(2258      currentTime,2259      boundaryFiber,2260      suspenseConfig,2261    );2262  }2263  // TODO: Special case idle priority?2264  const root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime);2265  if (root !== null) {2266    ensureRootIsScheduled(root);2267    schedulePendingInteractions(root, retryTime);2268  }2269}2270export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {2271  const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2272  let retryTime = NoWork;2273  if (suspenseState !== null) {2274    retryTime = suspenseState.retryTime;2275  }2276  retryTimedOutBoundary(boundaryFiber, retryTime);2277}2278export function resolveRetryThenable(boundaryFiber: Fiber, thenable: Thenable) {2279  let retryTime = NoWork; // Default2280  let retryCache: WeakSet<Thenable> | Set<Thenable> | null;2281  if (enableSuspenseServerRenderer) {2282    switch (boundaryFiber.tag) {2283      case SuspenseComponent:2284        retryCache = boundaryFiber.stateNode;2285        const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2286        if (suspenseState !== null) {2287          retryTime = suspenseState.retryTime;2288        }2289        break;2290      case SuspenseListComponent:2291        retryCache = boundaryFiber.stateNode;2292        break;2293      default:2294        invariant(2295          false,2296          'Pinged unknown suspense boundary type. ' +2297            'This is probably a bug in React.',2298        );2299    }2300  } else {2301    retryCache = boundaryFiber.stateNode;2302  }2303  if (retryCache !== null) {2304    // The thenable resolved, so we no longer need to memoize, because it will2305    // never be thrown again.2306    retryCache.delete(thenable);2307  }2308  retryTimedOutBoundary(boundaryFiber, retryTime);2309}2310// Computes the next Just Noticeable Difference (JND) boundary.2311// The theory is that a person can't tell the difference between small differences in time.2312// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable2313// difference in the experience. However, waiting for longer might mean that we can avoid2314// showing an intermediate loading state. The longer we have already waited, the harder it2315// is to tell small differences in time. Therefore, the longer we've already waited,2316// the longer we can wait additionally. At some point we have to give up though.2317// We pick a train model where the next boundary commits at a consistent schedule.2318// These particular numbers are vague estimates. We expect to adjust them based on research.2319function jnd(timeElapsed: number) {2320  return timeElapsed < 1202321    ? 1202322    : timeElapsed < 4802323    ? 4802324    : timeElapsed < 10802325    ? 10802326    : timeElapsed < 19202327    ? 19202328    : timeElapsed < 30002329    ? 30002330    : timeElapsed < 43202331    ? 43202332    : ceil(timeElapsed / 1960) * 1960;2333}2334function computeMsUntilSuspenseLoadingDelay(2335  mostRecentEventTime: ExpirationTime,2336  committedExpirationTime: ExpirationTime,2337  suspenseConfig: SuspenseConfig,2338) {2339  const busyMinDurationMs = (suspenseConfig.busyMinDurationMs: any) | 0;2340  if (busyMinDurationMs <= 0) {2341    return 0;2342  }2343  const busyDelayMs = (suspenseConfig.busyDelayMs: any) | 0;2344  // Compute the time until this render pass would expire.2345  const currentTimeMs: number = now();2346  const eventTimeMs: number = inferTimeFromExpirationTimeWithSuspenseConfig(2347    mostRecentEventTime,2348    suspenseConfig,2349  );2350  const timeElapsed = currentTimeMs - eventTimeMs;2351  if (timeElapsed <= busyDelayMs) {2352    // If we haven't yet waited longer than the initial delay, we don't2353    // have to wait any additional time.2354    return 0;2355  }2356  const msUntilTimeout = busyDelayMs + busyMinDurationMs - timeElapsed;2357  // This is the value that is passed to `setTimeout`.2358  return msUntilTimeout;2359}2360function checkForNestedUpdates() {...Using AI Code Generation
1const playwright = require('playwright');2(async () => {3  const browser = await playwright.chromium.launch();4  const context = await browser.newContext();5  const page = await context.newPage();6  const time = await page.evaluate(() => {7    const { inferTimeFromExpirationTimeWithSuspenseConfig } = window.playwrightInternal;8    return inferTimeFromExpirationTimeWithSuspenseConfig(2000, { timeoutMs: 10000 });9  });10  console.log(time);11  await browser.close();12})();13const playwright = require('playwright');14(async () => {15  const browser = await playwright.chromium.launch();16  const context = await browser.newContext();17  const page = await context.newPage();18  await page.waitForSelector('div', { timeout: 10000 });19  await browser.close();20})();21const playwright = require('playwright');22(async () => {23  const browser = await playwright.chromium.launch();24  const context = await browser.newContext();25  const page = await context.newPage();26  await page.waitForFunction(() => !!document.querySelector('div'), { timeout: 10000 });27  await browser.close();28})();29const playwright = require('playwright');30(async () => {31  const browser = await playwright.chromium.launch();32  const context = await browser.newContext();33  const page = await context.newPage();34  await page.waitForTimeout(10000);35  await browser.close();36})();37const playwright = require('playwright');38(async () => {39  const browser = await playwright.chromium.launch();40  const context = await browser.newContext();41  const page = await context.newPage();Using AI Code Generation
1const { chromium } = require('playwright');2const { inferTimeFromExpirationTimeWithSuspenseConfig } = require('playwright/lib/server/supplements/utils/schedulerWithReactIntegration');3(async () => {4    const browser = await chromium.launch();5    const context = await browser.newContext();6    const page = await context.newPage();7    const expirationTime = await page.evaluate(() => window.performance.timing.loadEventEnd);8    const suspenseConfig = await page.evaluate(() => window.__REACT_DEVTOOLS_GLOBAL_HOOK__.rendererInterfaces[0].getSuspenseConfig());9    const timeFromExpirationTime = inferTimeFromExpirationTimeWithSuspenseConfig(expirationTime, suspenseConfig);10    console.log(timeFromExpirationTime);11    await browser.close();12})();13### inferTimeFromExpirationTimeWithSuspenseConfig(expirationTime, suspenseConfig)14[MIT](LICENSE)Using AI Code Generation
1const {chromium} = require('playwright');2const browser = await chromium.launch();3const context = await browser.newContext();4const page = await context.newPage();5const {inferTimeFromExpirationTimeWithSuspenseConfig} = require('playwright/lib/internal/inferTimeFromExpirationTimeWithSuspenseConfig');6const time = inferTimeFromExpirationTimeWithSuspenseConfig(10000, {timeoutMs: 10000, busyDelayMs: 1000, busyMinDurationMs: 1000});7console.log(time);8await browser.close();Using AI Code Generation
1const { Playwright } = require('playwright');2const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;3const { Playwright } = require('playwright');4const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;5const { Playwright } = require('playwright');6const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;7const { Playwright } = require('playwright');8const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;9const { Playwright } = require('playwright');10const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;11const { Playwright } = require('playwright');12const { inferTimeFromExpirationTimeWithSuspenseConfig } = Playwright.Internal;Using AI Code Generation
1const { inferTimeFromExpirationTimeWithSuspenseConfig } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');2const expirationTime = 1000;3const suspenseConfig = { timeoutMs: 1000 };4const time = inferTimeFromExpirationTimeWithSuspenseConfig(expirationTime, suspenseConfig);5console.log(time);6### `page.waitForSelectorWithText(selector, text, options)`7const { chromium } = require('playwright');8(async () => {9  const browser = await chromium.launch();10  const page = await browser.newPage();11  await page.setContent('<div>hello</div><div>beautiful</div><div>world!</div>');12  const div = await page.waitForSelectorWithText('div', 'beautiful');13  console.log(await div.textContent());14  await browser.close();15})();16### `page.waitForXPathWithText(xpath, text, options)`Using AI Code Generation
1const { inferTimeFromExpirationTimeWithSuspenseConfig } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');2const expirationTime = 0;3const suspenseConfig = {4};5const result = inferTimeFromExpirationTimeWithSuspenseConfig(expirationTime, suspenseConfig);6console.log(result);Using AI Code Generation
1+    const { inferTimeFromExpirationTimeWithSuspenseConfig } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');2+    const { suspenseConfig } = require('playwright/lib/server/supplements/recorder/suspenseConfig.js');3+    console.log(inferTimeFromExpirationTimeWithSuspenseConfig(suspenseConfig, 10000));4+#### constructor: `SuspenseConfig(timeout: number, timeoutMs: number)`5+#### method: `SuspenseConfig.timeout()`6+#### method: `SuspenseConfig.timeoutMs()`7+### function: `setSuspenseConfig(config: SuspenseConfig)`8+### function: `getSuspenseConfig()`9+### function: `inferTimeFromExpirationTimeWithSuspenseConfig(config: SuspenseConfig, expirationTime: number)`10+### function: `inferTimeFromExpirationTime(expirationTime: number)`11+### function: `inferTimeFromSuspenseConfig()`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!!
