Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...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 }1684 function isAlreadyFailedLegacyErrorBoundary(instance) {1685 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);1686 }1687 function markLegacyErrorBoundaryAsFailed(instance) {1688 if (legacyErrorBoundariesThatAlreadyFailed === null) {1689 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);1690 } else {1691 legacyErrorBoundariesThatAlreadyFailed.add(instance);1692 }1693 }1694 function prepareToThrowUncaughtError(error) {1695 if (!hasUncaughtError) {1696 hasUncaughtError = true;1697 firstUncaughtError = error;1698 }1699 }1700 var onUncaughtError = prepareToThrowUncaughtError;1701 function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {1702 var errorInfo = createCapturedValue(error, sourceFiber);1703 var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane);1704 enqueueUpdate(rootFiber, update);1705 var eventTime = requestEventTime();1706 var root = markUpdateLaneFromFiberToRoot(rootFiber, SyncLane);1707 if (root !== null) {1708 markRootUpdated(root, SyncLane, eventTime);1709 ensureRootIsScheduled(root, eventTime);1710 schedulePendingInteractions(root, SyncLane);1711 }1712 }1713 function captureCommitPhaseError(sourceFiber, error) {1714 if (sourceFiber.tag === HostRoot) {1715 // Error was thrown at the root. There is no parent, so the root1716 // itself should capture it.1717 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);1718 return;1719 }1720 var fiber = sourceFiber.return;1721 while (fiber !== null) {1722 if (fiber.tag === HostRoot) {1723 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);1724 return;1725 } else if (fiber.tag === ClassComponent) {1726 var ctor = fiber.type;1727 var instance = fiber.stateNode;1728 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1729 var errorInfo = createCapturedValue(error, sourceFiber);1730 var update = createClassErrorUpdate(fiber, errorInfo, SyncLane);1731 enqueueUpdate(fiber, update);1732 var eventTime = requestEventTime();1733 var root = markUpdateLaneFromFiberToRoot(fiber, SyncLane);1734 if (root !== null) {1735 markRootUpdated(root, SyncLane, eventTime);1736 ensureRootIsScheduled(root, eventTime);1737 schedulePendingInteractions(root, SyncLane);1738 } else {1739 // This component has already been unmounted.1740 // We can't schedule any follow up work for the root because the fiber is already unmounted,1741 // but we can still call the log-only boundary so the error isn't swallowed.1742 //1743 // TODO This is only a temporary bandaid for the old reconciler fork.1744 // We can delete this special case once the new fork is merged.1745 if (typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1746 try {1747 instance.componentDidCatch(error, errorInfo);1748 } catch (errorToIgnore) {// TODO Ignore this error? Rethrow it?1749 // This is kind of an edge case.1750 }1751 }1752 }1753 return;1754 }1755 }1756 fiber = fiber.return;1757 }1758 }1759 function pingSuspendedRoot(root, wakeable, pingedLanes) {1760 var pingCache = root.pingCache;1761 if (pingCache !== null) {1762 // The wakeable resolved, so we no longer need to memoize, because it will1763 // never be thrown again.1764 pingCache.delete(wakeable);1765 }1766 var eventTime = requestEventTime();1767 markRootPinged(root, pingedLanes);1768 if (workInProgressRoot === root && isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)) {1769 // Received a ping at the same priority level at which we're currently1770 // rendering. We might want to restart this render. This should mirror1771 // the logic of whether or not a root suspends once it completes.1772 // TODO: If we're rendering sync either due to Sync, Batched or expired,1773 // we should probably never restart.1774 // If we're suspended with delay, or if it's a retry, we'll always suspend1775 // so we can always restart.1776 if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && includesOnlyRetries(workInProgressRootRenderLanes) && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) {1777 // Restart from the root.1778 prepareFreshStack(root, NoLanes);1779 } else {1780 // Even though we can't restart right now, we might get an1781 // opportunity later. So we mark this render as having a ping.1782 workInProgressRootPingedLanes = mergeLanes(workInProgressRootPingedLanes, pingedLanes);1783 }1784 }1785 ensureRootIsScheduled(root, eventTime);1786 schedulePendingInteractions(root, pingedLanes);1787 }1788 function retryTimedOutBoundary(boundaryFiber, retryLane) {1789 // The boundary fiber (a Suspense component or SuspenseList component)1790 // previously was rendered in its fallback state. One of the promises that1791 // suspended it has resolved, which means at least part of the tree was1792 // likely unblocked. Try rendering again, at a new expiration time.1793 if (retryLane === NoLane) {1794 retryLane = requestRetryLane(boundaryFiber);1795 } // TODO: Special case idle priority?1796 var eventTime = requestEventTime();1797 var root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);1798 if (root !== null) {1799 markRootUpdated(root, retryLane, eventTime);1800 ensureRootIsScheduled(root, eventTime);1801 schedulePendingInteractions(root, retryLane);1802 }1803 }1804 function retryDehydratedSuspenseBoundary(boundaryFiber) {1805 var suspenseState = boundaryFiber.memoizedState;1806 var retryLane = NoLane;1807 if (suspenseState !== null) {1808 retryLane = suspenseState.retryLane;1809 }1810 retryTimedOutBoundary(boundaryFiber, retryLane);1811 }1812 function resolveRetryWakeable(boundaryFiber, wakeable) {1813 var retryLane = NoLane; // Default1814 var retryCache;1815 {1816 switch (boundaryFiber.tag) {1817 case SuspenseComponent:1818 retryCache = boundaryFiber.stateNode;1819 var suspenseState = boundaryFiber.memoizedState;1820 if (suspenseState !== null) {1821 retryLane = suspenseState.retryLane;1822 }1823 break;1824 case SuspenseListComponent:1825 retryCache = boundaryFiber.stateNode;1826 break;1827 default:1828 {1829 {1830 throw Error( "Pinged unknown suspense boundary type. This is probably a bug in React." );1831 }1832 }1833 }1834 }1835 if (retryCache !== null) {1836 // The wakeable resolved, so we no longer need to memoize, because it will1837 // never be thrown again.1838 retryCache.delete(wakeable);1839 }1840 retryTimedOutBoundary(boundaryFiber, retryLane);1841 } // Computes the next Just Noticeable Difference (JND) boundary.1842 // The theory is that a person can't tell the difference between small differences in time.1843 // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable1844 // difference in the experience. However, waiting for longer might mean that we can avoid1845 // showing an intermediate loading state. The longer we have already waited, the harder it1846 // is to tell small differences in time. Therefore, the longer we've already waited,1847 // the longer we can wait additionally. At some point we have to give up though.1848 // We pick a train model where the next boundary commits at a consistent schedule.1849 // These particular numbers are vague estimates. We expect to adjust them based on research.1850 function jnd(timeElapsed) {1851 return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960;1852 }1853 function checkForNestedUpdates() {1854 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {1855 nestedUpdateCount = 0;1856 rootWithNestedUpdates = null;1857 {1858 {1859 throw Error( "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." );1860 }1861 }1862 }1863 {1864 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {1865 nestedPassiveUpdateCount = 0;1866 error('Maximum update depth exceeded. This can happen when a component ' + "calls setState inside useEffect, but useEffect either doesn't " + 'have a dependency array, or one of the dependencies changes on ' + 'every render.');1867 }1868 }1869 }1870 function flushRenderPhaseStrictModeWarningsInDEV() {1871 {1872 ReactStrictModeWarnings.flushLegacyContextWarning();1873 {1874 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();1875 }1876 }1877 }1878 var didWarnStateUpdateForNotYetMountedComponent = null;1879 function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {1880 {1881 if ((executionContext & RenderContext) !== NoContext) {1882 // We let the other warning about render phase updates deal with this one.1883 return;1884 }1885 if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {1886 return;1887 }1888 var tag = fiber.tag;1889 if (tag !== IndeterminateComponent && tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1890 // Only warn for user-defined components, not internal ones like Suspense.1891 return;1892 } // We show the whole stack but dedupe on the top component's name because1893 // the problematic code almost always lies inside that component.1894 var componentName = getComponentName(fiber.type) || 'ReactComponent';1895 if (didWarnStateUpdateForNotYetMountedComponent !== null) {1896 if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {1897 return;1898 }1899 didWarnStateUpdateForNotYetMountedComponent.add(componentName);1900 } else {1901 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);1902 }1903 var previousFiber = current;1904 try {1905 setCurrentFiber(fiber);1906 error("Can't perform a React state update on a component that hasn't mounted yet. " + 'This indicates that you have a side-effect in your render function that ' + 'asynchronously later calls tries to update the component. Move this work to ' + 'useEffect instead.');1907 } finally {1908 if (previousFiber) {1909 setCurrentFiber(fiber);1910 } else {1911 resetCurrentFiber();1912 }1913 }1914 }1915 }1916 var didWarnStateUpdateForUnmountedComponent = null;1917 function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {1918 {1919 var tag = fiber.tag;1920 if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1921 // Only warn for user-defined components, not internal ones like Suspense.1922 return;1923 } // If there are pending passive effects unmounts for this Fiber,1924 // we can assume that they would have prevented this update.1925 if ((fiber.flags & PassiveUnmountPendingDev) !== NoFlags) {1926 return;1927 } // We show the whole stack but dedupe on the top component's name because1928 // the problematic code almost always lies inside that component.1929 var componentName = getComponentName(fiber.type) || 'ReactComponent';1930 if (didWarnStateUpdateForUnmountedComponent !== null) {1931 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {1932 return;1933 }1934 didWarnStateUpdateForUnmountedComponent.add(componentName);1935 } else {1936 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);1937 }1938 if (isFlushingPassiveEffects) ; else {1939 var previousFiber = current;1940 try {1941 setCurrentFiber(fiber);1942 error("Can't perform a React state update on an unmounted component. This " + 'is a no-op, but it indicates a memory leak in your application. To ' + 'fix, cancel all subscriptions and asynchronous tasks in %s.', tag === ClassComponent ? 'the componentWillUnmount method' : 'a useEffect cleanup function');1943 } finally {1944 if (previousFiber) {1945 setCurrentFiber(fiber);1946 } else {1947 resetCurrentFiber();1948 }1949 }1950 }1951 }1952 }1953 var beginWork$1;1954 {1955 var dummyFiber = null;1956 beginWork$1 = function (current, unitOfWork, lanes) {1957 // If a component throws an error, we replay it again in a synchronously1958 // dispatched event, so that the debugger will treat it as an uncaught1959 // error See ReactErrorUtils for more information.1960 // Before entering the begin phase, copy the work-in-progress onto a dummy1961 // fiber. If beginWork throws, we'll use this to reset the state.1962 var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork);1963 try {1964 return beginWork(current, unitOfWork, lanes);1965 } catch (originalError) {1966 if (originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') {1967 // Don't replay promises. Treat everything else like an error.1968 throw originalError;1969 } // Keep this code in sync with handleError; any changes here must have1970 // corresponding changes there.1971 resetContextDependencies();1972 resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the1973 // same fiber again.1974 // Unwind the failed stack frame1975 unwindInterruptedWork(unitOfWork); // Restore the original properties of the fiber.1976 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);1977 if ( unitOfWork.mode & ProfileMode) {1978 // Reset the profiler timer.1979 startProfilerTimer(unitOfWork);1980 } // Run beginWork again.1981 invokeGuardedCallback(null, beginWork, null, current, unitOfWork, lanes);1982 if (hasCaughtError()) {1983 var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.1984 // Rethrow this error instead of the original one.1985 throw replayError;1986 } else {1987 // This branch is reachable if the render phase is impure.1988 throw originalError;1989 }1990 }1991 };1992 }1993 var didWarnAboutUpdateInRender = false;1994 var didWarnAboutUpdateInRenderForAnotherComponent;1995 {1996 didWarnAboutUpdateInRenderForAnotherComponent = new Set();1997 }1998 function warnAboutRenderPhaseUpdatesInDEV(fiber) {1999 {2000 if (isRendering && (executionContext & RenderContext) !== NoContext && !getIsUpdatingOpaqueValueInRenderPhaseInDEV()) {2001 switch (fiber.tag) {2002 case FunctionComponent:2003 case ForwardRef:2004 case SimpleMemoComponent:2005 {2006 var renderingComponentName = workInProgress && getComponentName(workInProgress.type) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed.2007 var dedupeKey = renderingComponentName;2008 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2009 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2010 var setStateComponentName = getComponentName(fiber.type) || 'Unknown';2011 error('Cannot update a component (`%s`) while rendering a ' + 'different component (`%s`). To locate the bad setState() call inside `%s`, ' + 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName);2012 }2013 break;2014 }2015 case ClassComponent:2016 {2017 if (!didWarnAboutUpdateInRender) {2018 error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.');2019 didWarnAboutUpdateInRender = true;2020 }2021 break;2022 }2023 }2024 }2025 }2026 } // a 'shared' variable that changes when act() opens/closes in tests.2027 var IsThisRendererActing = {2028 current: false2029 };2030 function warnIfNotScopedWithMatchingAct(fiber) {2031 {2032 if ( IsSomeRendererActing.current === true && IsThisRendererActing.current !== true) {2033 var previousFiber = current;2034 try {2035 setCurrentFiber(fiber);2036 error("It looks like you're using the wrong act() around your test interactions.\n" + 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' + '// for react-dom:\n' + // Break up imports to avoid accidentally parsing them as dependencies.2037 'import {act} fr' + "om 'react-dom/test-utils';\n" + '// ...\n' + 'act(() => ...);\n\n' + '// for react-test-renderer:\n' + // Break up imports to avoid accidentally parsing them as dependencies.2038 'import TestRenderer fr' + "om react-test-renderer';\n" + 'const {act} = TestRenderer;\n' + '// ...\n' + 'act(() => ...);');2039 } finally {2040 if (previousFiber) {2041 setCurrentFiber(fiber);2042 } else {2043 resetCurrentFiber();2044 }2045 }2046 }2047 }2048 }2049 function warnIfNotCurrentlyActingEffectsInDEV(fiber) {2050 {2051 if ( (fiber.mode & StrictMode) !== NoMode && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2052 error('An update to %s ran an effect, but was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));2053 }2054 }2055 }2056 function warnIfNotCurrentlyActingUpdatesInDEV(fiber) {2057 {2058 if ( executionContext === NoContext && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2059 var previousFiber = current;2060 try {2061 setCurrentFiber(fiber);2062 error('An update to %s inside a test was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));2063 } finally {2064 if (previousFiber) {2065 setCurrentFiber(fiber);2066 } else {2067 resetCurrentFiber();2068 }2069 }2070 }2071 }2072 }2073 var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; // In tests, we want to enforce a mocked scheduler.2074 var didWarnAboutUnmockedScheduler = false; // TODO Before we release concurrent mode, revisit this and decide whether a mocked2075 // scheduler is the actual recommendation. The alternative could be a testing build,2076 // a new lib, or whatever; we dunno just yet. This message is for early adopters2077 // to get their tests right.2078 function warnIfUnmockedScheduler(fiber) {2079 {2080 if (didWarnAboutUnmockedScheduler === false && unstable_flushAllWithoutAsserting === undefined) {2081 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2082 didWarnAboutUnmockedScheduler = true;2083 error('In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' + 'to guarantee consistent behaviour across tests and browsers. ' + 'For example, with jest: \n' + // Break up requires to avoid accidentally parsing them as dependencies.2084 "jest.mock('scheduler', () => require" + "('scheduler/unstable_mock'));\n\n" + 'For more info, visit https://reactjs.org/link/mock-scheduler');2085 }2086 }2087 }2088 }2089 function computeThreadID(root, lane) {2090 // Interaction threads are unique per root and expiration time.2091 // NOTE: Intentionally unsound cast. All that matters is that it's a number2092 // and it represents a batch of work. Could make a helper function instead,2093 // but meh this is fine for now.2094 return lane * 1000 + root.interactionThreadID;2095 }2096 function markSpawnedWork(lane) {2097 if (spawnedWorkDuringRender === null) {2098 spawnedWorkDuringRender = [lane];2099 } else {2100 spawnedWorkDuringRender.push(lane);2101 }2102 }2103 function scheduleInteractions(root, lane, interactions) {2104 if (interactions.size > 0) {2105 var pendingInteractionMap = root.pendingInteractionMap;2106 var pendingInteractions = pendingInteractionMap.get(lane);2107 if (pendingInteractions != null) {2108 interactions.forEach(function (interaction) {2109 if (!pendingInteractions.has(interaction)) {2110 // Update the pending async work count for previously unscheduled interaction.2111 interaction.__count++;2112 }2113 pendingInteractions.add(interaction);2114 });2115 } else {2116 pendingInteractionMap.set(lane, new Set(interactions)); // Update the pending async work count for the current interactions.2117 interactions.forEach(function (interaction) {2118 interaction.__count++;2119 });2120 }2121 var subscriber = __subscriberRef.current;2122 if (subscriber !== null) {2123 var threadID = computeThreadID(root, lane);2124 subscriber.onWorkScheduled(interactions, threadID);2125 }2126 }2127 }2128 function schedulePendingInteractions(root, lane) {2129 scheduleInteractions(root, lane, __interactionsRef.current);2130 }2131 function startWorkOnPendingInteractions(root, lanes) {2132 // we can accurately attribute time spent working on it, And so that cascading2133 // work triggered during the render phase will be associated with it.2134 var interactions = new Set();2135 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledLane) {2136 if (includesSomeLane(lanes, scheduledLane)) {2137 scheduledInteractions.forEach(function (interaction) {2138 return interactions.add(interaction);2139 });2140 }2141 }); // Store the current set of interactions on the FiberRoot for a few reasons:2142 // We can re-use it in hot functions like performConcurrentWorkOnRoot()2143 // without having to recalculate it. We will also use it in commitWork() to2144 // pass to any Profiler onRender() hooks. This also provides DevTools with a2145 // way to access it when the onCommitRoot() hook is called.2146 root.memoizedInteractions = interactions;2147 if (interactions.size > 0) {2148 var subscriber = __subscriberRef.current;2149 if (subscriber !== null) {2150 var threadID = computeThreadID(root, lanes);2151 try {2152 subscriber.onWorkStarted(interactions, threadID);2153 } catch (error) {2154 // If the subscriber throws, rethrow it in a separate task2155 scheduleCallback(ImmediatePriority$1, function () {2156 throw error;2157 });2158 }2159 }2160 }2161 }2162 function finishPendingInteractions(root, committedLanes) {2163 var remainingLanesAfterCommit = root.pendingLanes;2164 var subscriber;2165 try {2166 subscriber = __subscriberRef.current;2167 if (subscriber !== null && root.memoizedInteractions.size > 0) {2168 // FIXME: More than one lane can finish in a single commit.2169 var threadID = computeThreadID(root, committedLanes);2170 subscriber.onWorkStopped(root.memoizedInteractions, threadID);2171 }2172 } catch (error) {2173 // If the subscriber throws, rethrow it in a separate task2174 scheduleCallback(ImmediatePriority$1, function () {2175 throw error;2176 });...
ReactFiberScheduler.js
Source:ReactFiberScheduler.js
...1302 if (enableSchedulerTracing) {1303 // If there are no passive effects, then we can complete the pending1304 // interactions. Otherwise, we'll wait until after the passive effects1305 // are flushed.1306 finishPendingInteractions(root, expirationTime);1307 }1308 }1309 // Check if there's remaining work on this root1310 const remainingExpirationTime = root.firstPendingTime;1311 if (remainingExpirationTime !== NoWork) {1312 const currentTime = requestCurrentTime();1313 const priorityLevel = inferPriorityFromExpirationTime(1314 currentTime,1315 remainingExpirationTime,1316 );1317 scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime);1318 } else {1319 // If there's no remaining work, we can clear the set of already failed1320 // error boundaries.1321 legacyErrorBoundariesThatAlreadyFailed = null;1322 }1323 onCommitRoot(finishedWork.stateNode);1324 if (remainingExpirationTime === Sync) {1325 // Count the number of times the root synchronously re-renders without1326 // finishing. If there are too many, it indicates an infinite update loop.1327 if (root === rootWithNestedUpdates) {1328 nestedUpdateCount++;1329 } else {1330 nestedUpdateCount = 0;1331 rootWithNestedUpdates = root;1332 }1333 } else {1334 nestedUpdateCount = 0;1335 }1336 if (hasUncaughtError) {1337 hasUncaughtError = false;1338 const error = firstUncaughtError;1339 firstUncaughtError = null;1340 throw error;1341 }1342 if (workPhase === LegacyUnbatchedPhase) {1343 // This is a legacy edge case. We just committed the initial mount of1344 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1345 // synchronously, but layout updates should be deferred until the end1346 // of the batch.1347 return null;1348 }1349 // If layout work was scheduled, flush it now.1350 flushImmediateQueue();1351 return null;1352}1353function commitBeforeMutationEffects() {1354 while (nextEffect !== null) {1355 if ((nextEffect.effectTag & Snapshot) !== NoEffect) {1356 setCurrentDebugFiberInDEV(nextEffect);1357 recordEffect();1358 const current = nextEffect.alternate;1359 commitBeforeMutationEffectOnFiber(current, nextEffect);1360 resetCurrentDebugFiberInDEV();1361 }1362 nextEffect = nextEffect.nextEffect;1363 }1364}1365function commitMutationEffects() {1366 // TODO: Should probably move the bulk of this function to commitWork.1367 while (nextEffect !== null) {1368 setCurrentDebugFiberInDEV(nextEffect);1369 const effectTag = nextEffect.effectTag;1370 if (effectTag & ContentReset) {1371 commitResetTextContent(nextEffect);1372 }1373 if (effectTag & Ref) {1374 const current = nextEffect.alternate;1375 if (current !== null) {1376 commitDetachRef(current);1377 }1378 }1379 // The following switch statement is only concerned about placement,1380 // updates, and deletions. To avoid needing to add a case for every possible1381 // bitmap value, we remove the secondary effects from the effect tag and1382 // switch on that value.1383 let primaryEffectTag = effectTag & (Placement | Update | Deletion);1384 switch (primaryEffectTag) {1385 case Placement: {1386 commitPlacement(nextEffect);1387 // Clear the "placement" from effect tag so that we know that this is1388 // inserted, before any life-cycles like componentDidMount gets called.1389 // TODO: findDOMNode doesn't rely on this any more but isMounted does1390 // and isMounted is deprecated anyway so we should be able to kill this.1391 nextEffect.effectTag &= ~Placement;1392 break;1393 }1394 case PlacementAndUpdate: {1395 // Placement1396 commitPlacement(nextEffect);1397 // Clear the "placement" from effect tag so that we know that this is1398 // inserted, before any life-cycles like componentDidMount gets called.1399 nextEffect.effectTag &= ~Placement;1400 // Update1401 const current = nextEffect.alternate;1402 commitWork(current, nextEffect);1403 break;1404 }1405 case Update: {1406 const current = nextEffect.alternate;1407 commitWork(current, nextEffect);1408 break;1409 }1410 case Deletion: {1411 commitDeletion(nextEffect);1412 break;1413 }1414 }1415 // TODO: Only record a mutation effect if primaryEffectTag is non-zero.1416 recordEffect();1417 resetCurrentDebugFiberInDEV();1418 nextEffect = nextEffect.nextEffect;1419 }1420}1421function commitLayoutEffects(1422 root: FiberRoot,1423 committedExpirationTime: ExpirationTime,1424) {1425 // TODO: Should probably move the bulk of this function to commitWork.1426 while (nextEffect !== null) {1427 setCurrentDebugFiberInDEV(nextEffect);1428 const effectTag = nextEffect.effectTag;1429 if (effectTag & (Update | Callback)) {1430 recordEffect();1431 const current = nextEffect.alternate;1432 commitLayoutEffectOnFiber(1433 root,1434 current,1435 nextEffect,1436 committedExpirationTime,1437 );1438 }1439 if (effectTag & Ref) {1440 recordEffect();1441 commitAttachRef(nextEffect);1442 }1443 if (effectTag & Passive) {1444 rootDoesHavePassiveEffects = true;1445 }1446 resetCurrentDebugFiberInDEV();1447 nextEffect = nextEffect.nextEffect;1448 }1449}1450export function flushPassiveEffects() {1451 if (rootWithPendingPassiveEffects === null) {1452 return false;1453 }1454 const root = rootWithPendingPassiveEffects;1455 const expirationTime = pendingPassiveEffectsExpirationTime;1456 rootWithPendingPassiveEffects = null;1457 pendingPassiveEffectsExpirationTime = NoWork;1458 let prevInteractions: Set<Interaction> | null = null;1459 if (enableSchedulerTracing) {1460 prevInteractions = __interactionsRef.current;1461 __interactionsRef.current = root.memoizedInteractions;1462 }1463 invariant(1464 workPhase !== RenderPhase && workPhase !== CommitPhase,1465 'Cannot flush passive effects while already rendering.',1466 );1467 const prevWorkPhase = workPhase;1468 workPhase = CommitPhase;1469 // Note: This currently assumes there are no passive effects on the root1470 // fiber, because the root is not part of its own effect list. This could1471 // change in the future.1472 let effect = root.current.firstEffect;1473 while (effect !== null) {1474 if (__DEV__) {1475 setCurrentDebugFiberInDEV(effect);1476 invokeGuardedCallback(null, commitPassiveHookEffects, null, effect);1477 if (hasCaughtError()) {1478 invariant(effect !== null, 'Should be working on an effect.');1479 const error = clearCaughtError();1480 captureCommitPhaseError(effect, error);1481 }1482 resetCurrentDebugFiberInDEV();1483 } else {1484 try {1485 commitPassiveHookEffects(effect);1486 } catch (error) {1487 invariant(effect !== null, 'Should be working on an effect.');1488 captureCommitPhaseError(effect, error);1489 }1490 }1491 effect = effect.nextEffect;1492 }1493 if (enableSchedulerTracing) {1494 __interactionsRef.current = ((prevInteractions: any): Set<Interaction>);1495 finishPendingInteractions(root, expirationTime);1496 }1497 workPhase = prevWorkPhase;1498 flushImmediateQueue();1499 // If additional passive effects were scheduled, increment a counter. If this1500 // exceeds the limit, we'll fire a warning.1501 nestedPassiveUpdateCount =1502 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;1503 return true;1504}1505export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {1506 return (1507 legacyErrorBoundariesThatAlreadyFailed !== null &&1508 legacyErrorBoundariesThatAlreadyFailed.has(instance)1509 );1510}1511export function markLegacyErrorBoundaryAsFailed(instance: mixed) {1512 if (legacyErrorBoundariesThatAlreadyFailed === null) {1513 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);1514 } else {1515 legacyErrorBoundariesThatAlreadyFailed.add(instance);1516 }1517}1518function prepareToThrowUncaughtError(error: mixed) {1519 if (!hasUncaughtError) {1520 hasUncaughtError = true;1521 firstUncaughtError = error;1522 }1523}1524export const onUncaughtError = prepareToThrowUncaughtError;1525function captureCommitPhaseErrorOnRoot(1526 rootFiber: Fiber,1527 sourceFiber: Fiber,1528 error: mixed,1529) {1530 const errorInfo = createCapturedValue(error, sourceFiber);1531 const update = createRootErrorUpdate(rootFiber, errorInfo, Sync);1532 enqueueUpdate(rootFiber, update);1533 const root = markUpdateTimeFromFiberToRoot(rootFiber, Sync);1534 if (root !== null) {1535 scheduleCallbackForRoot(root, ImmediatePriority, Sync);1536 }1537}1538export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {1539 if (sourceFiber.tag === HostRoot) {1540 // Error was thrown at the root. There is no parent, so the root1541 // itself should capture it.1542 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);1543 return;1544 }1545 let fiber = sourceFiber.return;1546 while (fiber !== null) {1547 if (fiber.tag === HostRoot) {1548 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);1549 return;1550 } else if (fiber.tag === ClassComponent) {1551 const ctor = fiber.type;1552 const instance = fiber.stateNode;1553 if (1554 typeof ctor.getDerivedStateFromError === 'function' ||1555 (typeof instance.componentDidCatch === 'function' &&1556 !isAlreadyFailedLegacyErrorBoundary(instance))1557 ) {1558 const errorInfo = createCapturedValue(error, sourceFiber);1559 const update = createClassErrorUpdate(1560 fiber,1561 errorInfo,1562 // TODO: This is always sync1563 Sync,1564 );1565 enqueueUpdate(fiber, update);1566 const root = markUpdateTimeFromFiberToRoot(fiber, Sync);1567 if (root !== null) {1568 scheduleCallbackForRoot(root, ImmediatePriority, Sync);1569 }1570 return;1571 }1572 }1573 fiber = fiber.return;1574 }1575}1576export function pingSuspendedRoot(1577 root: FiberRoot,1578 thenable: Thenable,1579 suspendedTime: ExpirationTime,1580) {1581 const pingCache = root.pingCache;1582 if (pingCache !== null) {1583 // The thenable resolved, so we no longer need to memoize, because it will1584 // never be thrown again.1585 pingCache.delete(thenable);1586 }1587 if (workInProgressRoot === root && renderExpirationTime === suspendedTime) {1588 // Received a ping at the same priority level at which we're currently1589 // rendering. Restart from the root. Don't need to schedule a ping because1590 // we're already working on this tree.1591 prepareFreshStack(root, renderExpirationTime);1592 return;1593 }1594 const lastPendingTime = root.lastPendingTime;1595 if (lastPendingTime < suspendedTime) {1596 // The root is no longer suspended at this time.1597 return;1598 }1599 const pingTime = root.pingTime;1600 if (pingTime !== NoWork && pingTime < suspendedTime) {1601 // There's already a lower priority ping scheduled.1602 return;1603 }1604 // Mark the time at which this ping was scheduled.1605 root.pingTime = suspendedTime;1606 const currentTime = requestCurrentTime();1607 const priorityLevel = inferPriorityFromExpirationTime(1608 currentTime,1609 suspendedTime,1610 );1611 scheduleCallbackForRoot(root, priorityLevel, suspendedTime);1612}1613export function retryTimedOutBoundary(boundaryFiber: Fiber) {1614 // The boundary fiber (a Suspense component) previously timed out and was1615 // rendered in its fallback state. One of the promises that suspended it has1616 // resolved, which means at least part of the tree was likely unblocked. Try1617 // rendering again, at a new expiration time.1618 const currentTime = requestCurrentTime();1619 const retryTime = computeExpirationForFiber(currentTime, boundaryFiber);1620 // TODO: Special case idle priority?1621 const priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime);1622 const root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime);1623 if (root !== null) {1624 scheduleCallbackForRoot(root, priorityLevel, retryTime);1625 }1626}1627export function resolveRetryThenable(boundaryFiber: Fiber, thenable: Thenable) {1628 let retryCache: WeakSet<Thenable> | Set<Thenable> | null;1629 if (enableSuspenseServerRenderer) {1630 switch (boundaryFiber.tag) {1631 case SuspenseComponent:1632 retryCache = boundaryFiber.stateNode;1633 break;1634 case DehydratedSuspenseComponent:1635 retryCache = boundaryFiber.memoizedState;1636 break;1637 default:1638 invariant(1639 false,1640 'Pinged unknown suspense boundary type. ' +1641 'This is probably a bug in React.',1642 );1643 }1644 } else {1645 retryCache = boundaryFiber.stateNode;1646 }1647 if (retryCache !== null) {1648 // The thenable resolved, so we no longer need to memoize, because it will1649 // never be thrown again.1650 retryCache.delete(thenable);1651 }1652 retryTimedOutBoundary(boundaryFiber);1653}1654// Computes the next Just Noticeable Difference (JND) boundary.1655// The theory is that a person can't tell the difference between small differences in time.1656// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable1657// difference in the experience. However, waiting for longer might mean that we can avoid1658// showing an intermediate loading state. The longer we have already waited, the harder it1659// is to tell small differences in time. Therefore, the longer we've already waited,1660// the longer we can wait additionally. At some point we have to give up though.1661// We pick a train model where the next boundary commits at a consistent schedule.1662// These particular numbers are vague estimates. We expect to adjust them based on research.1663function jnd(timeElapsed: number) {1664 return timeElapsed < 1201665 ? 1201666 : timeElapsed < 4801667 ? 4801668 : timeElapsed < 10801669 ? 10801670 : timeElapsed < 19201671 ? 19201672 : timeElapsed < 30001673 ? 30001674 : timeElapsed < 43201675 ? 43201676 : ceil(timeElapsed / 1960) * 1960;1677}1678function computeMsUntilTimeout(1679 mostRecentEventTime: ExpirationTime,1680 committedExpirationTime: ExpirationTime,1681) {1682 if (disableYielding) {1683 // Timeout immediately when yielding is disabled.1684 return 0;1685 }1686 const eventTimeMs: number = inferTimeFromExpirationTime(mostRecentEventTime);1687 const currentTimeMs: number = now();1688 const timeElapsed = currentTimeMs - eventTimeMs;1689 let msUntilTimeout = jnd(timeElapsed) - timeElapsed;1690 // Compute the time until this render pass would expire.1691 const timeUntilExpirationMs =1692 expirationTimeToMs(committedExpirationTime) - currentTimeMs;1693 // Clamp the timeout to the expiration time.1694 // TODO: Once the event time is exact instead of inferred from expiration time1695 // we don't need this.1696 if (timeUntilExpirationMs < msUntilTimeout) {1697 msUntilTimeout = timeUntilExpirationMs;1698 }1699 // This is the value that is passed to `setTimeout`.1700 return msUntilTimeout;1701}1702function checkForNestedUpdates() {1703 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {1704 nestedUpdateCount = 0;1705 rootWithNestedUpdates = null;1706 invariant(1707 false,1708 'Maximum update depth exceeded. This can happen when a component ' +1709 'repeatedly calls setState inside componentWillUpdate or ' +1710 'componentDidUpdate. React limits the number of nested updates to ' +1711 'prevent infinite loops.',1712 );1713 }1714 if (__DEV__) {1715 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {1716 nestedPassiveUpdateCount = 0;1717 warning(1718 false,1719 'Maximum update depth exceeded. This can happen when a component ' +1720 "calls setState inside useEffect, but useEffect either doesn't " +1721 'have a dependency array, or one of the dependencies changes on ' +1722 'every render.',1723 );1724 }1725 }1726}1727function flushRenderPhaseStrictModeWarningsInDEV() {1728 if (__DEV__) {1729 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();1730 ReactStrictModeWarnings.flushLegacyContextWarning();1731 if (warnAboutDeprecatedLifecycles) {1732 ReactStrictModeWarnings.flushPendingDeprecationWarnings();1733 }1734 }1735}1736function stopFinishedWorkLoopTimer() {1737 const didCompleteRoot = true;1738 stopWorkLoopTimer(interruptedBy, didCompleteRoot);1739 interruptedBy = null;1740}1741function stopInterruptedWorkLoopTimer() {1742 // TODO: Track which fiber caused the interruption.1743 const didCompleteRoot = false;1744 stopWorkLoopTimer(interruptedBy, didCompleteRoot);1745 interruptedBy = null;1746}1747function checkForInterruption(1748 fiberThatReceivedUpdate: Fiber,1749 updateExpirationTime: ExpirationTime,1750) {1751 if (1752 enableUserTimingAPI &&1753 workInProgressRoot !== null &&1754 updateExpirationTime > renderExpirationTime1755 ) {1756 interruptedBy = fiberThatReceivedUpdate;1757 }1758}1759let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;1760function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {1761 if (__DEV__) {1762 const tag = fiber.tag;1763 if (1764 tag !== HostRoot &&1765 tag !== ClassComponent &&1766 tag !== FunctionComponent &&1767 tag !== ForwardRef &&1768 tag !== MemoComponent &&1769 tag !== SimpleMemoComponent1770 ) {1771 // Only warn for user-defined components, not internal ones like Suspense.1772 return;1773 }1774 // We show the whole stack but dedupe on the top component's name because1775 // the problematic code almost always lies inside that component.1776 const componentName = getComponentName(fiber.type) || 'ReactComponent';1777 if (didWarnStateUpdateForUnmountedComponent !== null) {1778 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {1779 return;1780 }1781 didWarnStateUpdateForUnmountedComponent.add(componentName);1782 } else {1783 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);1784 }1785 warningWithoutStack(1786 false,1787 "Can't perform a React state update on an unmounted component. This " +1788 'is a no-op, but it indicates a memory leak in your application. To ' +1789 'fix, cancel all subscriptions and asynchronous tasks in %s.%s',1790 tag === ClassComponent1791 ? 'the componentWillUnmount method'1792 : 'a useEffect cleanup function',1793 getStackByFiberInDevAndProd(fiber),1794 );1795 }1796}1797let beginWork;1798if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {1799 let dummyFiber = null;1800 beginWork = (current, unitOfWork, expirationTime) => {1801 // If a component throws an error, we replay it again in a synchronously1802 // dispatched event, so that the debugger will treat it as an uncaught1803 // error See ReactErrorUtils for more information.1804 // Before entering the begin phase, copy the work-in-progress onto a dummy1805 // fiber. If beginWork throws, we'll use this to reset the state.1806 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(1807 dummyFiber,1808 unitOfWork,1809 );1810 try {1811 return originalBeginWork(current, unitOfWork, expirationTime);1812 } catch (originalError) {1813 if (1814 originalError !== null &&1815 typeof originalError === 'object' &&1816 typeof originalError.then === 'function'1817 ) {1818 // Don't replay promises. Treat everything else like an error.1819 throw originalError;1820 }1821 // Keep this code in sync with renderRoot; any changes here must have1822 // corresponding changes there.1823 resetContextDependencies();1824 resetHooks();1825 // Unwind the failed stack frame1826 unwindInterruptedWork(unitOfWork);1827 // Restore the original properties of the fiber.1828 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);1829 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {1830 // Reset the profiler timer.1831 startProfilerTimer(unitOfWork);1832 }1833 // Run beginWork again.1834 invokeGuardedCallback(1835 null,1836 originalBeginWork,1837 null,1838 current,1839 unitOfWork,1840 expirationTime,1841 );1842 if (hasCaughtError()) {1843 const replayError = clearCaughtError();1844 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.1845 // Rethrow this error instead of the original one.1846 throw replayError;1847 } else {1848 // This branch is reachable if the render phase is impure.1849 throw originalError;1850 }1851 }1852 };1853} else {1854 beginWork = originalBeginWork;1855}1856let didWarnAboutUpdateInRender = false;1857let didWarnAboutUpdateInGetChildContext = false;1858function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) {1859 if (__DEV__) {1860 if (fiber.tag === ClassComponent) {1861 switch (ReactCurrentDebugFiberPhaseInDEV) {1862 case 'getChildContext':1863 if (didWarnAboutUpdateInGetChildContext) {1864 return;1865 }1866 warningWithoutStack(1867 false,1868 'setState(...): Cannot call setState() inside getChildContext()',1869 );1870 didWarnAboutUpdateInGetChildContext = true;1871 break;1872 case 'render':1873 if (didWarnAboutUpdateInRender) {1874 return;1875 }1876 warningWithoutStack(1877 false,1878 'Cannot update during an existing state transition (such as ' +1879 'within `render`). Render methods should be a pure function of ' +1880 'props and state.',1881 );1882 didWarnAboutUpdateInRender = true;1883 break;1884 }1885 }1886 }1887}1888function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {1889 if (__DEV__) {1890 if (1891 workPhase === NotWorking &&1892 ReactShouldWarnActingUpdates.current === false1893 ) {1894 warningWithoutStack(1895 false,1896 'An update to %s inside a test was not wrapped in act(...).\n\n' +1897 'When testing, code that causes React state updates should be ' +1898 'wrapped into act(...):\n\n' +1899 'act(() => {\n' +1900 ' /* fire events that update state */\n' +1901 '});\n' +1902 '/* assert on the output */\n\n' +1903 "This ensures that you're testing the behavior the user would see " +1904 'in the browser.' +1905 ' Learn more at https://fb.me/react-wrap-tests-with-act' +1906 '%s',1907 getComponentName(fiber.type),1908 getStackByFiberInDevAndProd(fiber),1909 );1910 }1911 }1912}1913export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;1914function computeThreadID(root, expirationTime) {1915 // Interaction threads are unique per root and expiration time.1916 return expirationTime * 1000 + root.interactionThreadID;1917}1918function schedulePendingInteraction(root, expirationTime) {1919 // This is called when work is scheduled on a root. It sets up a pending1920 // interaction, which is completed once the work commits.1921 if (!enableSchedulerTracing) {1922 return;1923 }1924 const interactions = __interactionsRef.current;1925 if (interactions.size > 0) {1926 const pendingInteractionMap = root.pendingInteractionMap;1927 const pendingInteractions = pendingInteractionMap.get(expirationTime);1928 if (pendingInteractions != null) {1929 interactions.forEach(interaction => {1930 if (!pendingInteractions.has(interaction)) {1931 // Update the pending async work count for previously unscheduled interaction.1932 interaction.__count++;1933 }1934 pendingInteractions.add(interaction);1935 });1936 } else {1937 pendingInteractionMap.set(expirationTime, new Set(interactions));1938 // Update the pending async work count for the current interactions.1939 interactions.forEach(interaction => {1940 interaction.__count++;1941 });1942 }1943 const subscriber = __subscriberRef.current;1944 if (subscriber !== null) {1945 const threadID = computeThreadID(root, expirationTime);1946 subscriber.onWorkScheduled(interactions, threadID);1947 }1948 }1949}1950function startWorkOnPendingInteraction(root, expirationTime) {1951 // This is called when new work is started on a root.1952 if (!enableSchedulerTracing) {1953 return;1954 }1955 // Determine which interactions this batch of work currently includes, So that1956 // we can accurately attribute time spent working on it, And so that cascading1957 // work triggered during the render phase will be associated with it.1958 const interactions: Set<Interaction> = new Set();1959 root.pendingInteractionMap.forEach(1960 (scheduledInteractions, scheduledExpirationTime) => {1961 if (scheduledExpirationTime >= expirationTime) {1962 scheduledInteractions.forEach(interaction =>1963 interactions.add(interaction),1964 );1965 }1966 },1967 );1968 // Store the current set of interactions on the FiberRoot for a few reasons:1969 // We can re-use it in hot functions like renderRoot() without having to1970 // recalculate it. We will also use it in commitWork() to pass to any Profiler1971 // onRender() hooks. This also provides DevTools with a way to access it when1972 // the onCommitRoot() hook is called.1973 root.memoizedInteractions = interactions;1974 if (interactions.size > 0) {1975 const subscriber = __subscriberRef.current;1976 if (subscriber !== null) {1977 const threadID = computeThreadID(root, expirationTime);1978 try {1979 subscriber.onWorkStarted(interactions, threadID);1980 } catch (error) {1981 // If the subscriber throws, rethrow it in a separate task1982 scheduleCallback(ImmediatePriority, () => {1983 throw error;1984 });1985 }1986 }1987 }1988}1989function finishPendingInteractions(root, committedExpirationTime) {1990 if (!enableSchedulerTracing) {1991 return;1992 }1993 const earliestRemainingTimeAfterCommit = root.firstPendingTime;1994 let subscriber;1995 try {1996 subscriber = __subscriberRef.current;1997 if (subscriber !== null && root.memoizedInteractions.size > 0) {1998 const threadID = computeThreadID(root, committedExpirationTime);1999 subscriber.onWorkStopped(root.memoizedInteractions, threadID);2000 }2001 } catch (error) {2002 // If the subscriber throws, rethrow it in a separate task2003 scheduleCallback(ImmediatePriority, () => {...
ReactFiberScheduler.new.js
Source:ReactFiberScheduler.new.js
...1286 if (enableSchedulerTracing) {1287 // If there are no passive effects, then we can complete the pending1288 // interactions. Otherwise, we'll wait until after the passive effects1289 // are flushed.1290 finishPendingInteractions(root, expirationTime);1291 }1292 }1293 // Check if there's remaining work on this root1294 const remainingExpirationTime = root.firstPendingTime;1295 if (remainingExpirationTime !== NoWork) {1296 const currentTime = requestCurrentTime();1297 const priorityLevel = inferPriorityFromExpirationTime(1298 currentTime,1299 remainingExpirationTime,1300 );1301 scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime);1302 } else {1303 // If there's no remaining work, we can clear the set of already failed1304 // error boundaries.1305 legacyErrorBoundariesThatAlreadyFailed = null;1306 }1307 onCommitRoot(finishedWork.stateNode);1308 if (remainingExpirationTime === Sync) {1309 // Count the number of times the root synchronously re-renders without1310 // finishing. If there are too many, it indicates an infinite update loop.1311 if (root === rootWithNestedUpdates) {1312 nestedUpdateCount++;1313 } else {1314 nestedUpdateCount = 0;1315 rootWithNestedUpdates = root;1316 }1317 } else {1318 nestedUpdateCount = 0;1319 }1320 if (hasUncaughtError) {1321 hasUncaughtError = false;1322 const error = firstUncaughtError;1323 firstUncaughtError = null;1324 throw error;1325 }1326 if (workPhase === LegacyUnbatchedPhase) {1327 // This is a legacy edge case. We just committed the initial mount of1328 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1329 // synchronously, but layout updates should be deferred until the end1330 // of the batch.1331 return null;1332 }1333 // If layout work was scheduled, flush it now.1334 flushImmediateQueue();1335 return null;1336}1337function commitBeforeMutationEffects() {1338 while (nextEffect !== null) {1339 if ((nextEffect.effectTag & Snapshot) !== NoEffect) {1340 setCurrentDebugFiberInDEV(nextEffect);1341 recordEffect();1342 const current = nextEffect.alternate;1343 commitBeforeMutationEffectOnFiber(current, nextEffect);1344 resetCurrentDebugFiberInDEV();1345 }1346 nextEffect = nextEffect.nextEffect;1347 }1348}1349function commitMutationEffects() {1350 // TODO: Should probably move the bulk of this function to commitWork.1351 while (nextEffect !== null) {1352 setCurrentDebugFiberInDEV(nextEffect);1353 const effectTag = nextEffect.effectTag;1354 if (effectTag & ContentReset) {1355 commitResetTextContent(nextEffect);1356 }1357 if (effectTag & Ref) {1358 const current = nextEffect.alternate;1359 if (current !== null) {1360 commitDetachRef(current);1361 }1362 }1363 // The following switch statement is only concerned about placement,1364 // updates, and deletions. To avoid needing to add a case for every possible1365 // bitmap value, we remove the secondary effects from the effect tag and1366 // switch on that value.1367 let primaryEffectTag = effectTag & (Placement | Update | Deletion);1368 switch (primaryEffectTag) {1369 case Placement: {1370 commitPlacement(nextEffect);1371 // Clear the "placement" from effect tag so that we know that this is1372 // inserted, before any life-cycles like componentDidMount gets called.1373 // TODO: findDOMNode doesn't rely on this any more but isMounted does1374 // and isMounted is deprecated anyway so we should be able to kill this.1375 nextEffect.effectTag &= ~Placement;1376 break;1377 }1378 case PlacementAndUpdate: {1379 // Placement1380 commitPlacement(nextEffect);1381 // Clear the "placement" from effect tag so that we know that this is1382 // inserted, before any life-cycles like componentDidMount gets called.1383 nextEffect.effectTag &= ~Placement;1384 // Update1385 const current = nextEffect.alternate;1386 commitWork(current, nextEffect);1387 break;1388 }1389 case Update: {1390 const current = nextEffect.alternate;1391 commitWork(current, nextEffect);1392 break;1393 }1394 case Deletion: {1395 commitDeletion(nextEffect);1396 break;1397 }1398 }1399 // TODO: Only record a mutation effect if primaryEffectTag is non-zero.1400 recordEffect();1401 resetCurrentDebugFiberInDEV();1402 nextEffect = nextEffect.nextEffect;1403 }1404}1405function commitLayoutEffects(1406 root: FiberRoot,1407 committedExpirationTime: ExpirationTime,1408) {1409 // TODO: Should probably move the bulk of this function to commitWork.1410 while (nextEffect !== null) {1411 setCurrentDebugFiberInDEV(nextEffect);1412 const effectTag = nextEffect.effectTag;1413 if (effectTag & (Update | Callback)) {1414 recordEffect();1415 const current = nextEffect.alternate;1416 commitLayoutEffectOnFiber(1417 root,1418 current,1419 nextEffect,1420 committedExpirationTime,1421 );1422 }1423 if (effectTag & Ref) {1424 recordEffect();1425 commitAttachRef(nextEffect);1426 }1427 if (effectTag & Passive) {1428 rootDoesHavePassiveEffects = true;1429 }1430 resetCurrentDebugFiberInDEV();1431 nextEffect = nextEffect.nextEffect;1432 }1433}1434export function flushPassiveEffects() {1435 if (rootWithPendingPassiveEffects === null) {1436 return false;1437 }1438 const root = rootWithPendingPassiveEffects;1439 const expirationTime = pendingPassiveEffectsExpirationTime;1440 rootWithPendingPassiveEffects = null;1441 pendingPassiveEffectsExpirationTime = NoWork;1442 let prevInteractions: Set<Interaction> | null = null;1443 if (enableSchedulerTracing) {1444 prevInteractions = __interactionsRef.current;1445 __interactionsRef.current = root.memoizedInteractions;1446 }1447 invariant(1448 workPhase !== RenderPhase && workPhase !== CommitPhase,1449 'Cannot flush passive effects while already rendering.',1450 );1451 const prevWorkPhase = workPhase;1452 workPhase = CommitPhase;1453 // Note: This currently assumes there are no passive effects on the root1454 // fiber, because the root is not part of its own effect list. This could1455 // change in the future.1456 let effect = root.current.firstEffect;1457 while (effect !== null) {1458 if (__DEV__) {1459 setCurrentDebugFiberInDEV(effect);1460 invokeGuardedCallback(null, commitPassiveHookEffects, null, effect);1461 if (hasCaughtError()) {1462 invariant(effect !== null, 'Should be working on an effect.');1463 const error = clearCaughtError();1464 captureCommitPhaseError(effect, error);1465 }1466 resetCurrentDebugFiberInDEV();1467 } else {1468 try {1469 commitPassiveHookEffects(effect);1470 } catch (error) {1471 invariant(effect !== null, 'Should be working on an effect.');1472 captureCommitPhaseError(effect, error);1473 }1474 }1475 effect = effect.nextEffect;1476 }1477 if (enableSchedulerTracing) {1478 __interactionsRef.current = ((prevInteractions: any): Set<Interaction>);1479 finishPendingInteractions(root, expirationTime);1480 }1481 workPhase = prevWorkPhase;1482 flushImmediateQueue();1483 // If additional passive effects were scheduled, increment a counter. If this1484 // exceeds the limit, we'll fire a warning.1485 nestedPassiveUpdateCount =1486 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;1487 return true;1488}1489export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {1490 return (1491 legacyErrorBoundariesThatAlreadyFailed !== null &&1492 legacyErrorBoundariesThatAlreadyFailed.has(instance)1493 );1494}1495export function markLegacyErrorBoundaryAsFailed(instance: mixed) {1496 if (legacyErrorBoundariesThatAlreadyFailed === null) {1497 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);1498 } else {1499 legacyErrorBoundariesThatAlreadyFailed.add(instance);1500 }1501}1502function prepareToThrowUncaughtError(error: mixed) {1503 if (!hasUncaughtError) {1504 hasUncaughtError = true;1505 firstUncaughtError = error;1506 }1507}1508export const onUncaughtError = prepareToThrowUncaughtError;1509function captureCommitPhaseErrorOnRoot(1510 rootFiber: Fiber,1511 sourceFiber: Fiber,1512 error: mixed,1513) {1514 const errorInfo = createCapturedValue(error, sourceFiber);1515 const update = createRootErrorUpdate(rootFiber, errorInfo, Sync);1516 enqueueUpdate(rootFiber, update);1517 const root = markUpdateTimeFromFiberToRoot(rootFiber, Sync);1518 if (root !== null) {1519 scheduleCallbackForRoot(root, ImmediatePriority, Sync);1520 }1521}1522export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {1523 if (sourceFiber.tag === HostRoot) {1524 // Error was thrown at the root. There is no parent, so the root1525 // itself should capture it.1526 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);1527 return;1528 }1529 let fiber = sourceFiber.return;1530 while (fiber !== null) {1531 if (fiber.tag === HostRoot) {1532 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);1533 return;1534 } else if (fiber.tag === ClassComponent) {1535 const ctor = fiber.type;1536 const instance = fiber.stateNode;1537 if (1538 typeof ctor.getDerivedStateFromError === 'function' ||1539 (typeof instance.componentDidCatch === 'function' &&1540 !isAlreadyFailedLegacyErrorBoundary(instance))1541 ) {1542 const errorInfo = createCapturedValue(error, sourceFiber);1543 const update = createClassErrorUpdate(1544 fiber,1545 errorInfo,1546 // TODO: This is always sync1547 Sync,1548 );1549 enqueueUpdate(fiber, update);1550 const root = markUpdateTimeFromFiberToRoot(fiber, Sync);1551 if (root !== null) {1552 scheduleCallbackForRoot(root, ImmediatePriority, Sync);1553 }1554 return;1555 }1556 }1557 fiber = fiber.return;1558 }1559}1560export function pingSuspendedRoot(1561 root: FiberRoot,1562 thenable: Thenable,1563 suspendedTime: ExpirationTime,1564) {1565 const pingCache = root.pingCache;1566 if (pingCache !== null) {1567 // The thenable resolved, so we no longer need to memoize, because it will1568 // never be thrown again.1569 pingCache.delete(thenable);1570 }1571 if (workInProgressRoot === root && renderExpirationTime === suspendedTime) {1572 // Received a ping at the same priority level at which we're currently1573 // rendering. Restart from the root. Don't need to schedule a ping because1574 // we're already working on this tree.1575 prepareFreshStack(root, renderExpirationTime);1576 return;1577 }1578 const lastPendingTime = root.lastPendingTime;1579 if (lastPendingTime < suspendedTime) {1580 // The root is no longer suspended at this time.1581 return;1582 }1583 const pingTime = root.pingTime;1584 if (pingTime !== NoWork && pingTime < suspendedTime) {1585 // There's already a lower priority ping scheduled.1586 return;1587 }1588 // Mark the time at which this ping was scheduled.1589 root.pingTime = suspendedTime;1590 const currentTime = requestCurrentTime();1591 const priorityLevel = inferPriorityFromExpirationTime(1592 currentTime,1593 suspendedTime,1594 );1595 scheduleCallbackForRoot(root, priorityLevel, suspendedTime);1596}1597export function retryTimedOutBoundary(boundaryFiber: Fiber) {1598 // The boundary fiber (a Suspense component) previously timed out and was1599 // rendered in its fallback state. One of the promises that suspended it has1600 // resolved, which means at least part of the tree was likely unblocked. Try1601 // rendering again, at a new expiration time.1602 const currentTime = requestCurrentTime();1603 const retryTime = computeExpirationForFiber(currentTime, boundaryFiber);1604 // TODO: Special case idle priority?1605 const priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime);1606 const root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime);1607 if (root !== null) {1608 scheduleCallbackForRoot(root, priorityLevel, retryTime);1609 }1610}1611export function resolveRetryThenable(boundaryFiber: Fiber, thenable: Thenable) {1612 let retryCache: WeakSet<Thenable> | Set<Thenable> | null;1613 if (enableSuspenseServerRenderer) {1614 switch (boundaryFiber.tag) {1615 case SuspenseComponent:1616 retryCache = boundaryFiber.stateNode;1617 break;1618 case DehydratedSuspenseComponent:1619 retryCache = boundaryFiber.memoizedState;1620 break;1621 default:1622 invariant(1623 false,1624 'Pinged unknown suspense boundary type. ' +1625 'This is probably a bug in React.',1626 );1627 }1628 } else {1629 retryCache = boundaryFiber.stateNode;1630 }1631 if (retryCache !== null) {1632 // The thenable resolved, so we no longer need to memoize, because it will1633 // never be thrown again.1634 retryCache.delete(thenable);1635 }1636 retryTimedOutBoundary(boundaryFiber);1637}1638export function inferStartTimeFromExpirationTime(1639 root: FiberRoot,1640 expirationTime: ExpirationTime,1641) {1642 // We don't know exactly when the update was scheduled, but we can infer an1643 // approximate start time from the expiration time.1644 const earliestExpirationTimeMs = expirationTimeToMs(root.firstPendingTime);1645 // TODO: Track this on the root instead. It's more accurate, doesn't rely on1646 // assumptions about priority, and isn't coupled to Scheduler details.1647 return earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;1648}1649function computeMsUntilTimeout(root, absoluteTimeoutMs) {1650 if (disableYielding) {1651 // Timeout immediately when yielding is disabled.1652 return 0;1653 }1654 // Find the earliest uncommitted expiration time in the tree, including1655 // work that is suspended. The timeout threshold cannot be longer than1656 // the overall expiration.1657 const earliestExpirationTimeMs = expirationTimeToMs(root.firstPendingTime);1658 if (earliestExpirationTimeMs < absoluteTimeoutMs) {1659 absoluteTimeoutMs = earliestExpirationTimeMs;1660 }1661 // Subtract the current time from the absolute timeout to get the number1662 // of milliseconds until the timeout. In other words, convert an absolute1663 // timestamp to a relative time. This is the value that is passed1664 // to `setTimeout`.1665 let msUntilTimeout = absoluteTimeoutMs - now();1666 return msUntilTimeout < 0 ? 0 : msUntilTimeout;1667}1668function checkForNestedUpdates() {1669 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {1670 nestedUpdateCount = 0;1671 rootWithNestedUpdates = null;1672 invariant(1673 false,1674 'Maximum update depth exceeded. This can happen when a component ' +1675 'repeatedly calls setState inside componentWillUpdate or ' +1676 'componentDidUpdate. React limits the number of nested updates to ' +1677 'prevent infinite loops.',1678 );1679 }1680 if (__DEV__) {1681 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {1682 nestedPassiveUpdateCount = 0;1683 warning(1684 false,1685 'Maximum update depth exceeded. This can happen when a component ' +1686 "calls setState inside useEffect, but useEffect either doesn't " +1687 'have a dependency array, or one of the dependencies changes on ' +1688 'every render.',1689 );1690 }1691 }1692}1693function flushRenderPhaseStrictModeWarningsInDEV() {1694 if (__DEV__) {1695 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();1696 ReactStrictModeWarnings.flushLegacyContextWarning();1697 if (warnAboutDeprecatedLifecycles) {1698 ReactStrictModeWarnings.flushPendingDeprecationWarnings();1699 }1700 }1701}1702function stopFinishedWorkLoopTimer() {1703 const didCompleteRoot = true;1704 stopWorkLoopTimer(interruptedBy, didCompleteRoot);1705 interruptedBy = null;1706}1707function stopInterruptedWorkLoopTimer() {1708 // TODO: Track which fiber caused the interruption.1709 const didCompleteRoot = false;1710 stopWorkLoopTimer(interruptedBy, didCompleteRoot);1711 interruptedBy = null;1712}1713function checkForInterruption(1714 fiberThatReceivedUpdate: Fiber,1715 updateExpirationTime: ExpirationTime,1716) {1717 if (1718 enableUserTimingAPI &&1719 workInProgressRoot !== null &&1720 updateExpirationTime > renderExpirationTime1721 ) {1722 interruptedBy = fiberThatReceivedUpdate;1723 }1724}1725let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;1726function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {1727 if (__DEV__) {1728 const tag = fiber.tag;1729 if (1730 tag !== HostRoot &&1731 tag !== ClassComponent &&1732 tag !== FunctionComponent &&1733 tag !== ForwardRef &&1734 tag !== MemoComponent &&1735 tag !== SimpleMemoComponent1736 ) {1737 // Only warn for user-defined components, not internal ones like Suspense.1738 return;1739 }1740 // We show the whole stack but dedupe on the top component's name because1741 // the problematic code almost always lies inside that component.1742 const componentName = getComponentName(fiber.type) || 'ReactComponent';1743 if (didWarnStateUpdateForUnmountedComponent !== null) {1744 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {1745 return;1746 }1747 didWarnStateUpdateForUnmountedComponent.add(componentName);1748 } else {1749 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);1750 }1751 warningWithoutStack(1752 false,1753 "Can't perform a React state update on an unmounted component. This " +1754 'is a no-op, but it indicates a memory leak in your application. To ' +1755 'fix, cancel all subscriptions and asynchronous tasks in %s.%s',1756 tag === ClassComponent1757 ? 'the componentWillUnmount method'1758 : 'a useEffect cleanup function',1759 getStackByFiberInDevAndProd(fiber),1760 );1761 }1762}1763let beginWork;1764if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {1765 let dummyFiber = null;1766 beginWork = (current, unitOfWork, expirationTime) => {1767 // If a component throws an error, we replay it again in a synchronously1768 // dispatched event, so that the debugger will treat it as an uncaught1769 // error See ReactErrorUtils for more information.1770 // Before entering the begin phase, copy the work-in-progress onto a dummy1771 // fiber. If beginWork throws, we'll use this to reset the state.1772 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(1773 dummyFiber,1774 unitOfWork,1775 );1776 try {1777 return originalBeginWork(current, unitOfWork, expirationTime);1778 } catch (originalError) {1779 if (1780 originalError !== null &&1781 typeof originalError === 'object' &&1782 typeof originalError.then === 'function'1783 ) {1784 // Don't replay promises. Treat everything else like an error.1785 throw originalError;1786 }1787 // Keep this code in sync with renderRoot; any changes here must have1788 // corresponding changes there.1789 resetContextDependencies();1790 resetHooks();1791 // Unwind the failed stack frame1792 unwindInterruptedWork(unitOfWork);1793 // Restore the original properties of the fiber.1794 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);1795 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {1796 // Reset the profiler timer.1797 startProfilerTimer(unitOfWork);1798 }1799 // Run beginWork again.1800 invokeGuardedCallback(1801 null,1802 originalBeginWork,1803 null,1804 current,1805 unitOfWork,1806 expirationTime,1807 );1808 if (hasCaughtError()) {1809 const replayError = clearCaughtError();1810 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.1811 // Rethrow this error instead of the original one.1812 throw replayError;1813 } else {1814 // This branch is reachable if the render phase is impure.1815 throw originalError;1816 }1817 }1818 };1819} else {1820 beginWork = originalBeginWork;1821}1822let didWarnAboutUpdateInRender = false;1823let didWarnAboutUpdateInGetChildContext = false;1824function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) {1825 if (__DEV__) {1826 if (fiber.tag === ClassComponent) {1827 switch (ReactCurrentDebugFiberPhaseInDEV) {1828 case 'getChildContext':1829 if (didWarnAboutUpdateInGetChildContext) {1830 return;1831 }1832 warningWithoutStack(1833 false,1834 'setState(...): Cannot call setState() inside getChildContext()',1835 );1836 didWarnAboutUpdateInGetChildContext = true;1837 break;1838 case 'render':1839 if (didWarnAboutUpdateInRender) {1840 return;1841 }1842 warningWithoutStack(1843 false,1844 'Cannot update during an existing state transition (such as ' +1845 'within `render`). Render methods should be a pure function of ' +1846 'props and state.',1847 );1848 didWarnAboutUpdateInRender = true;1849 break;1850 }1851 }1852 }1853}1854function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {1855 if (__DEV__) {1856 if (1857 workPhase === NotWorking &&1858 ReactShouldWarnActingUpdates.current === false1859 ) {1860 warningWithoutStack(1861 false,1862 'An update to %s inside a test was not wrapped in act(...).\n\n' +1863 'When testing, code that causes React state updates should be ' +1864 'wrapped into act(...):\n\n' +1865 'act(() => {\n' +1866 ' /* fire events that update state */\n' +1867 '});\n' +1868 '/* assert on the output */\n\n' +1869 "This ensures that you're testing the behavior the user would see " +1870 'in the browser.' +1871 ' Learn more at https://fb.me/react-wrap-tests-with-act' +1872 '%s',1873 getComponentName(fiber.type),1874 getStackByFiberInDevAndProd(fiber),1875 );1876 }1877 }1878}1879export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;1880function computeThreadID(root, expirationTime) {1881 // Interaction threads are unique per root and expiration time.1882 return expirationTime * 1000 + root.interactionThreadID;1883}1884function schedulePendingInteraction(root, expirationTime) {1885 // This is called when work is scheduled on a root. It sets up a pending1886 // interaction, which is completed once the work commits.1887 if (!enableSchedulerTracing) {1888 return;1889 }1890 const interactions = __interactionsRef.current;1891 if (interactions.size > 0) {1892 const pendingInteractionMap = root.pendingInteractionMap;1893 const pendingInteractions = pendingInteractionMap.get(expirationTime);1894 if (pendingInteractions != null) {1895 interactions.forEach(interaction => {1896 if (!pendingInteractions.has(interaction)) {1897 // Update the pending async work count for previously unscheduled interaction.1898 interaction.__count++;1899 }1900 pendingInteractions.add(interaction);1901 });1902 } else {1903 pendingInteractionMap.set(expirationTime, new Set(interactions));1904 // Update the pending async work count for the current interactions.1905 interactions.forEach(interaction => {1906 interaction.__count++;1907 });1908 }1909 const subscriber = __subscriberRef.current;1910 if (subscriber !== null) {1911 const threadID = computeThreadID(root, expirationTime);1912 subscriber.onWorkScheduled(interactions, threadID);1913 }1914 }1915}1916function startWorkOnPendingInteraction(root, expirationTime) {1917 // This is called when new work is started on a root.1918 if (!enableSchedulerTracing) {1919 return;1920 }1921 // Determine which interactions this batch of work currently includes, So that1922 // we can accurately attribute time spent working on it, And so that cascading1923 // work triggered during the render phase will be associated with it.1924 const interactions: Set<Interaction> = new Set();1925 root.pendingInteractionMap.forEach(1926 (scheduledInteractions, scheduledExpirationTime) => {1927 if (scheduledExpirationTime >= expirationTime) {1928 scheduledInteractions.forEach(interaction =>1929 interactions.add(interaction),1930 );1931 }1932 },1933 );1934 // Store the current set of interactions on the FiberRoot for a few reasons:1935 // We can re-use it in hot functions like renderRoot() without having to1936 // recalculate it. We will also use it in commitWork() to pass to any Profiler1937 // onRender() hooks. This also provides DevTools with a way to access it when1938 // the onCommitRoot() hook is called.1939 root.memoizedInteractions = interactions;1940 if (interactions.size > 0) {1941 const subscriber = __subscriberRef.current;1942 if (subscriber !== null) {1943 const threadID = computeThreadID(root, expirationTime);1944 try {1945 subscriber.onWorkStarted(interactions, threadID);1946 } catch (error) {1947 // If the subscriber throws, rethrow it in a separate task1948 scheduleCallback(ImmediatePriority, () => {1949 throw error;1950 });1951 }1952 }1953 }1954}1955function finishPendingInteractions(root, committedExpirationTime) {1956 if (!enableSchedulerTracing) {1957 return;1958 }1959 const earliestRemainingTimeAfterCommit = root.firstPendingTime;1960 let subscriber;1961 try {1962 subscriber = __subscriberRef.current;1963 if (subscriber !== null && root.memoizedInteractions.size > 0) {1964 const threadID = computeThreadID(root, committedExpirationTime);1965 subscriber.onWorkStopped(root.memoizedInteractions, threadID);1966 }1967 } catch (error) {1968 // If the subscriber throws, rethrow it in a separate task1969 scheduleCallback(ImmediatePriority, () => {...
4 - commitWork.js
Source:4 - commitWork.js
...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
...203 // If there are no passive effects, then we can complete the pending interactions.204 // Otherwise, we'll wait until after the passive effects are flushed.205 // Wait to do this until after remaining work has been scheduled,206 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.207 finishPendingInteractions(root, expirationTime);208 }209 }210 if (remainingExpirationTime === Sync) {211 // Count the number of times the root synchronously re-renders without212 // finishing. If there are too many, it indicates an infinite update loop.213 if (root === rootWithNestedUpdates) {214 nestedUpdateCount++;215 } else {216 nestedUpdateCount = 0;217 rootWithNestedUpdates = root;218 }219 } else {220 nestedUpdateCount = 0;221 }...
flushPassiveEffectsImpl.js
Source:flushPassiveEffectsImpl.js
...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;...
ReactNativeRenderer-profiling.js
Source:ReactNativeRenderer-profiling.js
...5 }6 }7+ performWork(0, !0);8 }9 function finishPendingInteractions(root, committedExpirationTime) {...
ReactFabric-profiling.js
Source:ReactFabric-profiling.js
...5 }6 }7+ performWork(0, !0);8 }9 function finishPendingInteractions(root, committedExpirationTime) {...
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.waitForLoadState('networkidle');7 await page.evaluate(() => {8 return new Promise((resolve) => {9 setTimeout(() => {10 console.log('done');11 resolve();12 }, 5000);13 });14 });15 await page._delegate._connection.send('Playwright.finishPendingInteractions');16 await page.screenshot({ path: 'screenshot.png' });17 await browser.close();18})();19Error: Protocol error (Playwright.finishPendingInteractions): 'Playwright.finishPendingInteractions' wasn't found20const { chromium } = require('playwright');21(async () => {22 const browser = await chromium.launch();23 const context = await browser.newContext();24 const page = await context.newPage();25 await page.waitForLoadState('networkidle');26 await page.evaluate(() => {27 return new Promise((resolve) => {28 setTimeout(() => {29 console.log('done');30 resolve();31 }, 5000);32 });33 });34 await page._delegate._connection.send('Playwright.finishPendingInteractions');35 await page.screenshot({ path: 'screenshot.png' });36 await browser.close();37})();38Error: Protocol error (Playwright.finishPendingInteractions): 'Playwright.finishPendingInteractions' wasn't found39const { chromium } = require('playwright
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.screenshot({ path: "example.png" });7 await browser.close();8 await context._browserContext._browser._defaultContext._connection._transport._ws._finishPendingInteractions()9})();
Using AI Code Generation
1const { chromium } = require('playwright');2const playwright = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.click('text=About');8 await page.waitForNavigation();9 await playwright._finishPendingInteractions();10 await browser.close();11})();12@karthik-bhagavathula Thank you! I tried it, but it seems that the _finishPendingInteractions method is not available in the playwright package. I'm using version 1.12.3. I tried to import it from the playwright-core package, but I got this error:13Error: Protocol error (DOM.describeNode): Node with given id does not belong to the document14module.exports = {
Using AI Code Generation
1const { finishPendingInteractions } = require('playwright/lib/server/frames');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 await page.click('input[name="q"]');7 await page.keyboard.type('Hello World');8 await finishPendingInteractions(page);9 await browser.close();10})();11const { test, expect } = require('@playwright/test');12test('should finish pending interactions', async ({ page }) => {13 await page.click('input[name="q"]');14 await page.keyboard.type('Hello World');15 await page.finishPendingInteractions();16 expect(await page.$('input[name="q"]')).toBeTruthy();17});18import { test, expect } from '@playwright/test';19test('should finish pending interactions', async ({ page }) => {20 await page.click('input[name="q"]');21 await page.keyboard.type('Hello World');22 await page.finishPendingInteractions();23 expect(await page.$('input[name="q"]')).toBeTruthy();24});25const { test, expect } = require('@playwright/test');26test('should finish pending interactions', async ({ page }) => {27 await page.click('input[name="q"]');28 await page.keyboard.type('Hello World');29 await page.finishPendingInteractions();30 expect(await page.$('input[name="q"]')).toBeTruthy();31});32import { test, expect } from '@playwright/test';33test('should finish pending interactions', async ({ page }) => {34 await page.click('input[name="q"]');35 await page.keyboard.type('Hello World');36 await page.finishPendingInteractions();37 expect(await page.$('input[name="q"]')).toBeTruthy();38});39const { test, expect } = require('@playwright/test');40test('should finish pending interactions', async ({ page }) => {41 await page.click('input[name="q"]');42 await page.keyboard.type('Hello World');
Using AI Code Generation
1const { finishPendingInteractions } = require('playwright');2await finishPendingInteractions();3const { finishPendingInteractions } = require('playwright');4await finishPendingInteractions();5const { finishPendingInteractions } = require('playwright');6await finishPendingInteractions();7const { finishPendingInteractions } = require('playwright');8await finishPendingInteractions();9const { finishPendingInteractions } = require('playwright');10await finishPendingInteractions();11const { finishPendingInteractions } = require('playwright');12await finishPendingInteractions();13const { finishPendingInteractions } = require('playwright');14await finishPendingInteractions();15const { finishPendingInteractions } = require('playwright');16await finishPendingInteractions();17const { finishPendingInteractions } = require('playwright');18await finishPendingInteractions();19const { finishPendingInteractions } = require('playwright');20await finishPendingInteractions();21const { finishPendingInteractions } = require('playwright');22await finishPendingInteractions();23const { finishPendingInteractions } = require('playwright');24await finishPendingInteractions();25const { finishPendingInteractions } = require('playwright');26await finishPendingInteractions();27const { finishPendingInteractions } = require('playwright');28await finishPendingInteractions();29const { finishPendingInteractions } = require('playwright');30await finishPendingInteractions();
Using AI Code Generation
1import { chromium } from 'playwright';2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 await context.addInitScript(() => {6 window.__finishPendingInteractions = () => {7 return new Promise((resolve) => {8 window.requestIdleCallback(resolve);9 });10 };11 });12 const page = await context.newPage();13 await page.evaluate(() => {14 const input = document.querySelector('input');15 input.value = 'Hello World!';16 input.dispatchEvent(new Event('input'));17 });18 await page.__finishPendingInteractions();19 await page.screenshot({ path: 'google.png' });20 await browser.close();21})();
Using AI Code Generation
1const {chromium} = require('playwright');2const {finishPendingInteractions} = require('playwright/lib/internal/inspectorInstrumentation');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.click('input[type="text"]');8 await page.type('input[type="text"]', 'This is a test');9 await finishPendingInteractions();10 await browser.close();11})();
Using AI Code Generation
1async function main() {2 const browser = await chromium.launch();3 const context = await browser.newContext();4 const page = await context.newPage();5 await page.click('text=Get started');6 await page.waitForSelector('text=Install with npm');7 await context.close();8 await browser.close();9}10main();11async function main() {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 await page.click('text=Get started');16 await page.waitForSelector('text=Install with npm');17 await context.close();18 await browser.close();19}20main();21async function main() {22 const browser = await chromium.launch();23 const context = await browser.newContext();24 const page = await context.newPage();25 await page.click('text=Get started');26 await page.waitForSelector('text=Install with npm');27 await context.close();28 await browser.close();29}30main();
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!!