Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js
...1302}1303function popDispatcher(prevDispatcher) {1304 ReactCurrentDispatcher.current = prevDispatcher;1305}1306function pushInteractions(root) {1307 if (enableSchedulerTracing) {1308 const prevInteractions: Set<Interaction> | null = __interactionsRef.current;1309 __interactionsRef.current = root.memoizedInteractions;1310 return prevInteractions;1311 }1312 return null;1313}1314function popInteractions(prevInteractions) {1315 if (enableSchedulerTracing) {1316 __interactionsRef.current = prevInteractions;1317 }1318}1319export function markCommitTimeOfFallback() {1320 globalMostRecentFallbackTime = now();1321}1322export function markSkippedUpdateLanes(lane: Lane | Lanes): void {1323 workInProgressRootSkippedLanes = mergeLanes(1324 lane,1325 workInProgressRootSkippedLanes,1326 );1327}1328export function renderDidSuspend(): void {1329 if (workInProgressRootExitStatus === RootIncomplete) {1330 workInProgressRootExitStatus = RootSuspended;1331 }1332}1333export function renderDidSuspendDelayIfPossible(): void {1334 if (1335 workInProgressRootExitStatus === RootIncomplete ||1336 workInProgressRootExitStatus === RootSuspended1337 ) {1338 workInProgressRootExitStatus = RootSuspendedWithDelay;1339 }1340 // Check if there are updates that we skipped tree that might have unblocked1341 // this render.1342 if (1343 workInProgressRoot !== null &&1344 (includesNonIdleWork(workInProgressRootSkippedLanes) ||1345 includesNonIdleWork(workInProgressRootUpdatedLanes))1346 ) {1347 // Mark the current render as suspended so that we switch to working on1348 // the updates that were skipped. Usually we only suspend at the end of1349 // the render phase.1350 // TODO: We should probably always mark the root as suspended immediately1351 // (inside this function), since by suspending at the end of the render1352 // phase introduces a potential mistake where we suspend lanes that were1353 // pinged or updated while we were rendering.1354 markRootSuspended(workInProgressRoot, workInProgressRootRenderLanes);1355 }1356}1357export function renderDidError() {1358 if (workInProgressRootExitStatus !== RootCompleted) {1359 workInProgressRootExitStatus = RootErrored;1360 }1361}1362// Called during render to determine if anything has suspended.1363// Returns false if we're not sure.1364export function renderHasNotSuspendedYet(): boolean {1365 // If something errored or completed, we can't really be sure,1366 // so those are false.1367 return workInProgressRootExitStatus === RootIncomplete;1368}1369function renderRootSync(root: FiberRoot, lanes: Lanes) {1370 const prevExecutionContext = executionContext;1371 executionContext |= RenderContext;1372 const prevDispatcher = pushDispatcher();1373 // If the root or lanes have changed, throw out the existing stack1374 // and prepare a fresh one. Otherwise we'll continue where we left off.1375 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1376 prepareFreshStack(root, lanes);1377 startWorkOnPendingInteractions(root, lanes);1378 }1379 const prevInteractions = pushInteractions(root);1380 if (__DEV__) {1381 if (enableDebugTracing) {1382 logRenderStarted(lanes);1383 }1384 }1385 if (enableSchedulingProfiler) {1386 markRenderStarted(lanes);1387 }1388 do {1389 try {1390 workLoopSync();1391 break;1392 } catch (thrownValue) {1393 handleError(root, thrownValue);1394 }1395 } while (true);1396 resetContextDependencies();1397 if (enableSchedulerTracing) {1398 popInteractions(((prevInteractions: any): Set<Interaction>));1399 }1400 executionContext = prevExecutionContext;1401 popDispatcher(prevDispatcher);1402 if (workInProgress !== null) {1403 // This is a sync render, so we should have finished the whole tree.1404 invariant(1405 false,1406 'Cannot commit an incomplete root. This error is likely caused by a ' +1407 'bug in React. Please file an issue.',1408 );1409 }1410 if (__DEV__) {1411 if (enableDebugTracing) {1412 logRenderStopped();1413 }1414 }1415 if (enableSchedulingProfiler) {1416 markRenderStopped();1417 }1418 // Set this to null to indicate there's no in-progress render.1419 workInProgressRoot = null;1420 workInProgressRootRenderLanes = NoLanes;1421 return workInProgressRootExitStatus;1422}1423// The work loop is an extremely hot path. Tell Closure not to inline it.1424/** @noinline */1425function workLoopSync() {1426 // Already timed out, so perform work without checking if we need to yield.1427 while (workInProgress !== null) {1428 performUnitOfWork(workInProgress);1429 }1430}1431function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {1432 const prevExecutionContext = executionContext;1433 executionContext |= RenderContext;1434 const prevDispatcher = pushDispatcher();1435 // If the root or lanes have changed, throw out the existing stack1436 // and prepare a fresh one. Otherwise we'll continue where we left off.1437 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {1438 resetRenderTimer();1439 prepareFreshStack(root, lanes);1440 startWorkOnPendingInteractions(root, lanes);1441 }1442 const prevInteractions = pushInteractions(root);1443 if (__DEV__) {1444 if (enableDebugTracing) {1445 logRenderStarted(lanes);1446 }1447 }1448 if (enableSchedulingProfiler) {1449 markRenderStarted(lanes);1450 }1451 do {1452 try {1453 workLoopConcurrent();1454 break;1455 } catch (thrownValue) {1456 handleError(root, thrownValue);1457 }1458 } while (true);1459 resetContextDependencies();1460 if (enableSchedulerTracing) {1461 popInteractions(((prevInteractions: any): Set<Interaction>));1462 }1463 popDispatcher(prevDispatcher);1464 executionContext = prevExecutionContext;1465 if (__DEV__) {1466 if (enableDebugTracing) {1467 logRenderStopped();1468 }1469 }1470 // Check if the tree has completed.1471 if (workInProgress !== null) {1472 // Still work remaining.1473 if (enableSchedulingProfiler) {1474 markRenderYielded();1475 }1476 return RootIncomplete;1477 } else {1478 // Completed the tree.1479 if (enableSchedulingProfiler) {1480 markRenderStopped();1481 }1482 // Set this to null to indicate there's no in-progress render.1483 workInProgressRoot = null;1484 workInProgressRootRenderLanes = NoLanes;1485 // Return the final exit status.1486 return workInProgressRootExitStatus;1487 }1488}1489/** @noinline */1490function workLoopConcurrent() {1491 // Perform work until Scheduler asks us to yield1492 while (workInProgress !== null && !shouldYield()) {1493 performUnitOfWork(workInProgress);1494 }1495}1496function performUnitOfWork(unitOfWork: Fiber): void {1497 // The current, flushed, state of this fiber is the alternate. Ideally1498 // nothing should rely on this, but relying on it here means that we don't1499 // need an additional field on the work in progress.1500 const current = unitOfWork.alternate;1501 setCurrentDebugFiberInDEV(unitOfWork);1502 let next;1503 if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {1504 startProfilerTimer(unitOfWork);1505 next = beginWork(current, unitOfWork, subtreeRenderLanes);1506 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);1507 } else {1508 next = beginWork(current, unitOfWork, subtreeRenderLanes);1509 }1510 resetCurrentDebugFiberInDEV();1511 unitOfWork.memoizedProps = unitOfWork.pendingProps;1512 if (next === null) {1513 // If this doesn't spawn new work, complete the current work.1514 completeUnitOfWork(unitOfWork);1515 } else {1516 workInProgress = next;1517 }1518 ReactCurrentOwner.current = null;1519}1520function completeUnitOfWork(unitOfWork: Fiber): void {1521 // Attempt to complete the current unit of work, then move to the next1522 // sibling. If there are no more siblings, return to the parent fiber.1523 let completedWork = unitOfWork;1524 do {1525 // The current, flushed, state of this fiber is the alternate. Ideally1526 // nothing should rely on this, but relying on it here means that we don't1527 // need an additional field on the work in progress.1528 const current = completedWork.alternate;1529 const returnFiber = completedWork.return;1530 // Check if the work completed or if something threw.1531 if ((completedWork.flags & Incomplete) === NoFlags) {1532 setCurrentDebugFiberInDEV(completedWork);1533 let next;1534 if (1535 !enableProfilerTimer ||1536 (completedWork.mode & ProfileMode) === NoMode1537 ) {1538 next = completeWork(current, completedWork, subtreeRenderLanes);1539 } else {1540 startProfilerTimer(completedWork);1541 next = completeWork(current, completedWork, subtreeRenderLanes);1542 // Update render duration assuming we didn't error.1543 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1544 }1545 resetCurrentDebugFiberInDEV();1546 if (next !== null) {1547 // Completing this fiber spawned new work. Work on that next.1548 workInProgress = next;1549 return;1550 }1551 } else {1552 // This fiber did not complete because something threw. Pop values off1553 // the stack without entering the complete phase. If this is a boundary,1554 // capture values if possible.1555 const next = unwindWork(completedWork, subtreeRenderLanes);1556 // Because this fiber did not complete, don't reset its expiration time.1557 if (next !== null) {1558 // If completing this work spawned new work, do that next. We'll come1559 // back here again.1560 // Since we're restarting, remove anything that is not a host effect1561 // from the effect tag.1562 next.flags &= HostEffectMask;1563 workInProgress = next;1564 return;1565 }1566 if (1567 enableProfilerTimer &&1568 (completedWork.mode & ProfileMode) !== NoMode1569 ) {1570 // Record the render duration for the fiber that errored.1571 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1572 // Include the time spent working on failed children before continuing.1573 let actualDuration = completedWork.actualDuration;1574 let child = completedWork.child;1575 while (child !== null) {1576 actualDuration += child.actualDuration;1577 child = child.sibling;1578 }1579 completedWork.actualDuration = actualDuration;1580 }1581 if (returnFiber !== null) {1582 // Mark the parent fiber as incomplete1583 returnFiber.flags |= Incomplete;1584 returnFiber.subtreeFlags = NoFlags;1585 returnFiber.deletions = null;1586 }1587 }1588 const siblingFiber = completedWork.sibling;1589 if (siblingFiber !== null) {1590 // If there is more work to do in this returnFiber, do that next.1591 workInProgress = siblingFiber;1592 return;1593 }1594 // Otherwise, return to the parent1595 completedWork = returnFiber;1596 // Update the next thing we're working on in case something throws.1597 workInProgress = completedWork;1598 } while (completedWork !== null);1599 // We've reached the root.1600 if (workInProgressRootExitStatus === RootIncomplete) {1601 workInProgressRootExitStatus = RootCompleted;1602 }1603}1604function commitRoot(root) {1605 const renderPriorityLevel = getCurrentPriorityLevel();1606 runWithPriority(1607 ImmediateSchedulerPriority,1608 commitRootImpl.bind(null, root, renderPriorityLevel),1609 );1610 return null;1611}1612function commitRootImpl(root, renderPriorityLevel) {1613 do {1614 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1615 // means `flushPassiveEffects` will sometimes result in additional1616 // passive effects. So we need to keep flushing in a loop until there are1617 // no more pending effects.1618 // TODO: Might be better if `flushPassiveEffects` did not automatically1619 // flush synchronous work at the end, to avoid factoring hazards like this.1620 flushPassiveEffects();1621 } while (rootWithPendingPassiveEffects !== null);1622 flushRenderPhaseStrictModeWarningsInDEV();1623 invariant(1624 (executionContext & (RenderContext | CommitContext)) === NoContext,1625 'Should not already be working.',1626 );1627 const finishedWork = root.finishedWork;1628 const lanes = root.finishedLanes;1629 if (__DEV__) {1630 if (enableDebugTracing) {1631 logCommitStarted(lanes);1632 }1633 }1634 if (enableSchedulingProfiler) {1635 markCommitStarted(lanes);1636 }1637 // 没æéè¦æ´æ°çFiberèç¹1638 if (finishedWork === null) {1639 if (__DEV__) {1640 if (enableDebugTracing) {1641 logCommitStopped();1642 }1643 }1644 if (enableSchedulingProfiler) {1645 markCommitStopped();1646 }1647 return null;1648 }1649 root.finishedWork = null;1650 root.finishedLanes = NoLanes;1651 invariant(1652 finishedWork !== root.current,1653 'Cannot commit the same tree as before. This error is likely caused by ' +1654 'a bug in React. Please file an issue.',1655 );1656 // commitRoot never returns a continuation; it always finishes synchronously.1657 // So we can clear these now to allow a new callback to be scheduled.1658 root.callbackNode = null;1659 // Update the first and last pending times on this root. The new first1660 // pending time is whatever is left on the root fiber.1661 // å并ææçéé1662 let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1663 markRootFinished(root, remainingLanes);1664 // Clear already finished discrete updates in case that a later call of1665 // `flushDiscreteUpdates` starts a useless render pass which may cancels1666 // a scheduled timeout.1667 if (rootsWithPendingDiscreteUpdates !== null) {1668 if (1669 !hasDiscreteLanes(remainingLanes) &&1670 rootsWithPendingDiscreteUpdates.has(root)1671 ) {1672 rootsWithPendingDiscreteUpdates.delete(root);1673 }1674 }1675 // 说ææ¬æ¬¡æ´æ°å·²ç»å®æäºï¼å°ä¸äºåééç½®1676 if (root === workInProgressRoot) {1677 // We can reset these now that they are finished.1678 workInProgressRoot = null;1679 workInProgress = null;1680 workInProgressRootRenderLanes = NoLanes;1681 } else {1682 // This indicates that the last root we worked on is not the same one that1683 // we're committing now. This most commonly happens when a suspended root1684 // times out.1685 }1686 // Check if there are any effects in the whole tree.1687 // TODO: This is left over from the effect list implementation, where we had1688 // to check for the existence of `firstEffect` to satsify Flow. I think the1689 // only other reason this optimization exists is because it affects profiling.1690 // Reconsider whether this is necessary.1691 const subtreeHasEffects =1692 (finishedWork.subtreeFlags &1693 (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1694 NoFlags;1695 const rootHasEffect =1696 (finishedWork.flags &1697 (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==1698 NoFlags;1699 // æéè¦å¤ççå¯ä½ç¨1700 if (subtreeHasEffects || rootHasEffect) {1701 let previousLanePriority;1702 if (decoupleUpdatePriorityFromScheduler) {1703 previousLanePriority = getCurrentUpdateLanePriority();1704 setCurrentUpdateLanePriority(SyncLanePriority);1705 }1706 // 设置æ§è¡ä¸ä¸æ1707 const prevExecutionContext = executionContext;1708 executionContext |= CommitContext;1709 const prevInteractions = pushInteractions(root);1710 // Reset this to null before calling lifecycles1711 ReactCurrentOwner.current = null;1712 // The commit phase is broken into several sub-phases. We do a separate pass1713 // of the effect list for each phase: all mutation effects come before all1714 // layout effects, and so on.1715 // The first phase a "before mutation" phase. We use this phase to read the1716 // state of the host tree right before we mutate it. This is where1717 // getSnapshotBeforeUpdate is called.1718 focusedInstanceHandle = prepareForCommit(root.containerInfo);1719 shouldFireAfterActiveInstanceBlur = false;1720 commitBeforeMutationEffects(finishedWork);1721 // We no longer need to track the active instance fiber1722 focusedInstanceHandle = null;1723 if (enableProfilerTimer) {1724 // Mark the current commit time to be shared by all Profilers in this1725 // batch. This enables them to be grouped later.1726 recordCommitTime();1727 }1728 // æDOMå
ç´ æ¸²æå°é¡µé¢ä¸1729 // The next phase is the mutation phase, where we mutate the host tree.1730 commitMutationEffects(finishedWork, root, renderPriorityLevel);1731 if (shouldFireAfterActiveInstanceBlur) {1732 afterActiveInstanceBlur();1733 }1734 resetAfterCommit(root.containerInfo);1735 // The work-in-progress tree is now the current tree. This must come after1736 // the mutation phase, so that the previous tree is still current during1737 // componentWillUnmount, but before the layout phase, so that the finished1738 // work is current during componentDidMount/Update.1739 // å¨æ¤ä¹åï¼root.current æåäºwork-in-progress tree1740 root.current = finishedWork;1741 // The next phase is the layout phase, where we call effects that read1742 // the host tree after it's been mutated. The idiomatic use case for this is1743 // layout, but class component lifecycles also fire here for legacy reasons.1744 if (__DEV__) {1745 if (enableDebugTracing) {1746 logLayoutEffectsStarted(lanes);1747 }1748 }1749 if (enableSchedulingProfiler) {1750 markLayoutEffectsStarted(lanes);1751 }1752 if (__DEV__) {1753 setCurrentDebugFiberInDEV(finishedWork);1754 invokeGuardedCallback(1755 null,1756 recursivelyCommitLayoutEffects,1757 null,1758 finishedWork,1759 root,1760 );1761 if (hasCaughtError()) {1762 const error = clearCaughtError();1763 captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1764 }1765 resetCurrentDebugFiberInDEV();1766 } else {1767 try {1768 recursivelyCommitLayoutEffects(finishedWork, root);1769 } catch (error) {1770 captureCommitPhaseErrorOnRoot(finishedWork, finishedWork, error);1771 }1772 }1773 if (__DEV__) {1774 if (enableDebugTracing) {1775 logLayoutEffectsStopped();1776 }1777 }1778 if (enableSchedulingProfiler) {1779 markLayoutEffectsStopped();1780 }1781 // If there are pending passive effects, schedule a callback to process them.1782 if (1783 (finishedWork.subtreeFlags & PassiveMask) !== NoFlags ||1784 (finishedWork.flags & PassiveMask) !== NoFlags1785 ) {1786 if (!rootDoesHavePassiveEffects) {1787 rootDoesHavePassiveEffects = true;1788 scheduleCallback(NormalSchedulerPriority, () => {1789 flushPassiveEffects();1790 return null;1791 });1792 }1793 }1794 // Tell Scheduler to yield at the end of the frame, so the browser has an1795 // opportunity to paint.1796 requestPaint();1797 if (enableSchedulerTracing) {1798 popInteractions(((prevInteractions: any): Set<Interaction>));1799 }1800 executionContext = prevExecutionContext;1801 if (decoupleUpdatePriorityFromScheduler && previousLanePriority != null) {1802 // Reset the priority to the previous non-sync value.1803 setCurrentUpdateLanePriority(previousLanePriority);1804 }1805 } else {1806 // No effects.1807 root.current = finishedWork;1808 // Measure these anyway so the flamegraph explicitly shows that there were1809 // no effects.1810 // TODO: Maybe there's a better way to report this.1811 if (enableProfilerTimer) {1812 recordCommitTime();1813 }1814 }1815 const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1816 if (rootDoesHavePassiveEffects) {1817 // This commit has passive effects. Stash a reference to them. But don't1818 // schedule a callback until after flushing layout work.1819 rootDoesHavePassiveEffects = false;1820 rootWithPendingPassiveEffects = root;1821 pendingPassiveEffectsLanes = lanes;1822 pendingPassiveEffectsRenderPriority = renderPriorityLevel;1823 }1824 // Read this again, since an effect might have updated it1825 remainingLanes = root.pendingLanes;1826 // Check if there's remaining work on this root1827 if (remainingLanes !== NoLanes) {1828 if (enableSchedulerTracing) {1829 if (spawnedWorkDuringRender !== null) {1830 const expirationTimes = spawnedWorkDuringRender;1831 spawnedWorkDuringRender = null;1832 for (let i = 0; i < expirationTimes.length; i++) {1833 scheduleInteractions(1834 root,1835 expirationTimes[i],1836 root.memoizedInteractions,1837 );1838 }1839 }1840 schedulePendingInteractions(root, remainingLanes);1841 }1842 } else {1843 // If there's no remaining work, we can clear the set of already failed1844 // error boundaries.1845 legacyErrorBoundariesThatAlreadyFailed = null;1846 }1847 if (__DEV__ && enableDoubleInvokingEffects) {1848 if (!rootDidHavePassiveEffects) {1849 commitDoubleInvokeEffectsInDEV(root.current, false);1850 }1851 }1852 if (enableSchedulerTracing) {1853 if (!rootDidHavePassiveEffects) {1854 // If there are no passive effects, then we can complete the pending interactions.1855 // Otherwise, we'll wait until after the passive effects are flushed.1856 // Wait to do this until after remaining work has been scheduled,1857 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1858 finishPendingInteractions(root, lanes);1859 }1860 }1861 if (remainingLanes === SyncLane) {1862 // Count the number of times the root synchronously re-renders without1863 // finishing. If there are too many, it indicates an infinite update loop.1864 if (root === rootWithNestedUpdates) {1865 nestedUpdateCount++;1866 } else {1867 nestedUpdateCount = 0;1868 rootWithNestedUpdates = root;1869 }1870 } else {1871 nestedUpdateCount = 0;1872 }1873 onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);1874 if (__DEV__) {1875 onCommitRootTestSelector();1876 }1877 // Always call this before exiting `commitRoot`, to ensure that any1878 // additional work on this root is scheduled.1879 ensureRootIsScheduled(root, now());1880 if (hasUncaughtError) {1881 hasUncaughtError = false;1882 const error = firstUncaughtError;1883 firstUncaughtError = null;1884 throw error;1885 }1886 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1887 if (__DEV__) {1888 if (enableDebugTracing) {1889 logCommitStopped();1890 }1891 }1892 if (enableSchedulingProfiler) {1893 markCommitStopped();1894 }1895 // This is a legacy edge case. We just committed the initial mount of1896 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1897 // synchronously, but layout updates should be deferred until the end1898 // of the batch.1899 return null;1900 }1901 // If layout work was scheduled, flush it now.1902 flushSyncCallbackQueue();1903 if (__DEV__) {1904 if (enableDebugTracing) {1905 logCommitStopped();1906 }1907 }1908 if (enableSchedulingProfiler) {1909 markCommitStopped();1910 }1911 return null;1912}1913function commitBeforeMutationEffects(firstChild: Fiber) {1914 let fiber = firstChild;1915 while (fiber !== null) {1916 // å¤çéè¦å é¤çfiber autoFocusãblur é»è¾ã1917 if (fiber.deletions !== null) {1918 commitBeforeMutationEffectsDeletions(fiber.deletions);1919 }1920 // éå½è°ç¨å¤çåèç¹1921 if (fiber.child !== null) {1922 const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;1923 if (primarySubtreeFlags !== NoFlags) {1924 commitBeforeMutationEffects(fiber.child);1925 }1926 }1927 if (__DEV__) {1928 setCurrentDebugFiberInDEV(fiber);1929 invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);1930 if (hasCaughtError()) {1931 const error = clearCaughtError();1932 captureCommitPhaseError(fiber, fiber.return, error);1933 }1934 resetCurrentDebugFiberInDEV();1935 } else {1936 try {1937 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1938 // å¼æ¥è°åº¦useEffect1939 commitBeforeMutationEffectsImpl(fiber);1940 } catch (error) {1941 captureCommitPhaseError(fiber, fiber.return, error);1942 }1943 }1944 // è¿åå
å¼èç¹ï¼æ¥ç循ç¯1945 fiber = fiber.sibling;1946 }1947}1948function commitBeforeMutationEffectsImpl(fiber: Fiber) {1949 const current = fiber.alternate;1950 const flags = fiber.flags;1951 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1952 // Check to see if the focused element was inside of a hidden (Suspense) subtree.1953 // TODO: Move this out of the hot path using a dedicated effect tag.1954 if (1955 fiber.tag === SuspenseComponent &&1956 isSuspenseBoundaryBeingHidden(current, fiber) &&1957 doesFiberContain(fiber, focusedInstanceHandle)1958 ) {1959 shouldFireAfterActiveInstanceBlur = true;1960 beforeActiveInstanceBlur();1961 }1962 }1963 if ((flags & Snapshot) !== NoFlags) {1964 setCurrentDebugFiberInDEV(fiber);1965 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1966 commitBeforeMutationEffectOnFiber(current, fiber);1967 resetCurrentDebugFiberInDEV();1968 }1969 // è°åº¦useEffect1970 if ((flags & Passive) !== NoFlags) {1971 // If there are passive effects, schedule a callback to flush at1972 // the earliest opportunity.1973 if (!rootDoesHavePassiveEffects) {1974 rootDoesHavePassiveEffects = true;1975 scheduleCallback(NormalSchedulerPriority, () => {1976 flushPassiveEffects();1977 return null;1978 });1979 }1980 }1981}1982function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {1983 for (let i = 0; i < deletions.length; i++) {1984 const fiber = deletions[i];1985 // TODO (effects) It would be nice to avoid calling doesFiberContain()1986 // Maybe we can repurpose one of the subtreeFlags positions for this instead?1987 // Use it to store which part of the tree the focused instance is in?1988 // This assumes we can safely determine that instance during the "render" phase.1989 if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {1990 shouldFireAfterActiveInstanceBlur = true;1991 beforeActiveInstanceBlur();1992 }1993 }1994}1995function commitMutationEffects(1996 firstChild: Fiber,1997 root: FiberRoot,1998 renderPriorityLevel: ReactPriorityLevel,1999) {2000 let fiber = firstChild;2001 while (fiber !== null) {2002 const deletions = fiber.deletions;2003 if (deletions !== null) {2004 commitMutationEffectsDeletions(2005 deletions,2006 fiber,2007 root,2008 renderPriorityLevel,2009 );2010 }2011 if (fiber.child !== null) {2012 const mutationFlags = fiber.subtreeFlags & MutationMask;2013 if (mutationFlags !== NoFlags) {2014 commitMutationEffects(fiber.child, root, renderPriorityLevel);2015 }2016 }2017 if (__DEV__) {2018 setCurrentDebugFiberInDEV(fiber);2019 invokeGuardedCallback(2020 null,2021 commitMutationEffectsImpl,2022 null,2023 fiber,2024 root,2025 renderPriorityLevel,2026 );2027 if (hasCaughtError()) {2028 const error = clearCaughtError();2029 captureCommitPhaseError(fiber, fiber.return, error);2030 }2031 resetCurrentDebugFiberInDEV();2032 } else {2033 try {2034 commitMutationEffectsImpl(fiber, root, renderPriorityLevel);2035 } catch (error) {2036 captureCommitPhaseError(fiber, fiber.return, error);2037 }2038 }2039 fiber = fiber.sibling;2040 }2041}2042function commitMutationEffectsImpl(2043 fiber: Fiber,2044 root: FiberRoot,2045 renderPriorityLevel,2046) {2047 const flags = fiber.flags;2048 if (flags & ContentReset) {2049 commitResetTextContent(fiber);2050 }2051 if (flags & Ref) {2052 const current = fiber.alternate;2053 if (current !== null) {2054 commitDetachRef(current);2055 }2056 if (enableScopeAPI) {2057 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.2058 if (fiber.tag === ScopeComponent) {2059 commitAttachRef(fiber);2060 }2061 }2062 }2063 // The following switch statement is only concerned about placement,2064 // updates, and deletions. To avoid needing to add a case for every possible2065 // bitmap value, we remove the secondary effects from the effect tag and2066 // switch on that value.2067 const primaryFlags = flags & (Placement | Update | Hydrating);2068 switch (primaryFlags) {2069 case Placement: {2070 commitPlacement(fiber);2071 // Clear the "placement" from effect tag so that we know that this is2072 // inserted, before any life-cycles like componentDidMount gets called.2073 // TODO: findDOMNode doesn't rely on this any more but isMounted does2074 // and isMounted is deprecated anyway so we should be able to kill this.2075 fiber.flags &= ~Placement;2076 break;2077 }2078 case PlacementAndUpdate: {2079 // Placement2080 commitPlacement(fiber);2081 // Clear the "placement" from effect tag so that we know that this is2082 // inserted, before any life-cycles like componentDidMount gets called.2083 fiber.flags &= ~Placement;2084 // Update2085 const current = fiber.alternate;2086 commitWork(current, fiber);2087 break;2088 }2089 case Hydrating: {2090 fiber.flags &= ~Hydrating;2091 break;2092 }2093 case HydratingAndUpdate: {2094 fiber.flags &= ~Hydrating;2095 // Update2096 const current = fiber.alternate;2097 commitWork(current, fiber);2098 break;2099 }2100 case Update: {2101 const current = fiber.alternate;2102 commitWork(current, fiber);2103 break;2104 }2105 }2106}2107function commitMutationEffectsDeletions(2108 deletions: Array<Fiber>,2109 nearestMountedAncestor: Fiber,2110 root: FiberRoot,2111 renderPriorityLevel,2112) {2113 for (let i = 0; i < deletions.length; i++) {2114 const childToDelete = deletions[i];2115 if (__DEV__) {2116 invokeGuardedCallback(2117 null,2118 commitDeletion,2119 null,2120 root,2121 childToDelete,2122 nearestMountedAncestor,2123 renderPriorityLevel,2124 );2125 if (hasCaughtError()) {2126 const error = clearCaughtError();2127 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2128 }2129 } else {2130 try {2131 commitDeletion(2132 root,2133 childToDelete,2134 nearestMountedAncestor,2135 renderPriorityLevel,2136 );2137 } catch (error) {2138 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2139 }2140 }2141 }2142}2143export function schedulePassiveEffectCallback() {2144 if (!rootDoesHavePassiveEffects) {2145 rootDoesHavePassiveEffects = true;2146 scheduleCallback(NormalSchedulerPriority, () => {2147 flushPassiveEffects();2148 return null;2149 });2150 }2151}2152export function flushPassiveEffects(): boolean {2153 // Returns whether passive effects were flushed.2154 if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {2155 const priorityLevel =2156 pendingPassiveEffectsRenderPriority > NormalSchedulerPriority2157 ? NormalSchedulerPriority2158 : pendingPassiveEffectsRenderPriority;2159 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;2160 if (decoupleUpdatePriorityFromScheduler) {2161 const previousLanePriority = getCurrentUpdateLanePriority();2162 try {2163 setCurrentUpdateLanePriority(2164 schedulerPriorityToLanePriority(priorityLevel),2165 );2166 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2167 } finally {2168 setCurrentUpdateLanePriority(previousLanePriority);2169 }2170 } else {2171 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2172 }2173 }2174 return false;2175}2176function flushPassiveMountEffects(root, firstChild: Fiber): void {2177 let fiber = firstChild;2178 while (fiber !== null) {2179 let prevProfilerOnStack = null;2180 if (enableProfilerTimer && enableProfilerCommitHooks) {2181 if (fiber.tag === Profiler) {2182 prevProfilerOnStack = nearestProfilerOnStack;2183 nearestProfilerOnStack = fiber;2184 }2185 }2186 const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;2187 if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {2188 flushPassiveMountEffects(root, fiber.child);2189 }2190 if ((fiber.flags & Passive) !== NoFlags) {2191 if (__DEV__) {2192 setCurrentDebugFiberInDEV(fiber);2193 invokeGuardedCallback(2194 null,2195 commitPassiveMountOnFiber,2196 null,2197 root,2198 fiber,2199 );2200 if (hasCaughtError()) {2201 const error = clearCaughtError();2202 captureCommitPhaseError(fiber, fiber.return, error);2203 }2204 resetCurrentDebugFiberInDEV();2205 } else {2206 try {2207 commitPassiveMountOnFiber(root, fiber);2208 } catch (error) {2209 captureCommitPhaseError(fiber, fiber.return, error);2210 }2211 }2212 }2213 if (enableProfilerTimer && enableProfilerCommitHooks) {2214 if (fiber.tag === Profiler) {2215 // Bubble times to the next nearest ancestor Profiler.2216 // After we process that Profiler, we'll bubble further up.2217 if (prevProfilerOnStack !== null) {2218 prevProfilerOnStack.stateNode.passiveEffectDuration +=2219 fiber.stateNode.passiveEffectDuration;2220 }2221 nearestProfilerOnStack = prevProfilerOnStack;2222 }2223 }2224 fiber = fiber.sibling;2225 }2226}2227function flushPassiveUnmountEffects(firstChild: Fiber): void {2228 let fiber = firstChild;2229 while (fiber !== null) {2230 const deletions = fiber.deletions;2231 if (deletions !== null) {2232 for (let i = 0; i < deletions.length; i++) {2233 const fiberToDelete = deletions[i];2234 flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber);2235 // Now that passive effects have been processed, it's safe to detach lingering pointers.2236 detachFiberAfterEffects(fiberToDelete);2237 }2238 }2239 const child = fiber.child;2240 if (child !== null) {2241 // If any children have passive effects then traverse the subtree.2242 // Note that this requires checking subtreeFlags of the current Fiber,2243 // rather than the subtreeFlags/effectsTag of the first child,2244 // since that would not cover passive effects in siblings.2245 const passiveFlags = fiber.subtreeFlags & PassiveMask;2246 if (passiveFlags !== NoFlags) {2247 flushPassiveUnmountEffects(child);2248 }2249 }2250 const primaryFlags = fiber.flags & Passive;2251 if (primaryFlags !== NoFlags) {2252 setCurrentDebugFiberInDEV(fiber);2253 commitPassiveUnmountOnFiber(fiber);2254 resetCurrentDebugFiberInDEV();2255 }2256 fiber = fiber.sibling;2257 }2258}2259function flushPassiveUnmountEffectsInsideOfDeletedTree(2260 fiberToDelete: Fiber,2261 nearestMountedAncestor: Fiber,2262): void {2263 if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {2264 // If any children have passive effects then traverse the subtree.2265 // Note that this requires checking subtreeFlags of the current Fiber,2266 // rather than the subtreeFlags/effectsTag of the first child,2267 // since that would not cover passive effects in siblings.2268 let child = fiberToDelete.child;2269 while (child !== null) {2270 flushPassiveUnmountEffectsInsideOfDeletedTree(2271 child,2272 nearestMountedAncestor,2273 );2274 child = child.sibling;2275 }2276 }2277 if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {2278 setCurrentDebugFiberInDEV(fiberToDelete);2279 commitPassiveUnmountInsideDeletedTreeOnFiber(2280 fiberToDelete,2281 nearestMountedAncestor,2282 );2283 resetCurrentDebugFiberInDEV();2284 }2285}2286function flushPassiveEffectsImpl() {2287 if (rootWithPendingPassiveEffects === null) {2288 return false;2289 }2290 const root = rootWithPendingPassiveEffects;2291 const lanes = pendingPassiveEffectsLanes;2292 rootWithPendingPassiveEffects = null;2293 pendingPassiveEffectsLanes = NoLanes;2294 invariant(2295 (executionContext & (RenderContext | CommitContext)) === NoContext,2296 'Cannot flush passive effects while already rendering.',2297 );2298 if (__DEV__) {2299 if (enableDebugTracing) {2300 logPassiveEffectsStarted(lanes);2301 }2302 }2303 if (enableSchedulingProfiler) {2304 markPassiveEffectsStarted(lanes);2305 }2306 if (__DEV__) {2307 isFlushingPassiveEffects = true;2308 }2309 const prevExecutionContext = executionContext;2310 executionContext |= CommitContext;2311 const prevInteractions = pushInteractions(root);2312 // It's important that ALL pending passive effect destroy functions are called2313 // before ANY passive effect create functions are called.2314 // Otherwise effects in sibling components might interfere with each other.2315 // e.g. a destroy function in one component may unintentionally override a ref2316 // value set by a create function in another component.2317 // Layout effects have the same constraint.2318 flushPassiveUnmountEffects(root.current);2319 flushPassiveMountEffects(root, root.current);2320 if (__DEV__) {2321 if (enableDebugTracing) {2322 logPassiveEffectsStopped();2323 }2324 }2325 if (enableSchedulingProfiler) {...
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...830 }831 function popDispatcher(prevDispatcher) {832 ReactCurrentDispatcher$2.current = prevDispatcher;833 }834 function pushInteractions(root) {835 {836 var prevInteractions = __interactionsRef.current;837 __interactionsRef.current = root.memoizedInteractions;838 return prevInteractions;839 }840 }841 function popInteractions(prevInteractions) {842 {843 __interactionsRef.current = prevInteractions;844 }845 }846 function markCommitTimeOfFallback() {847 globalMostRecentFallbackTime = now();848 }849 function markSkippedUpdateLanes(lane) {850 workInProgressRootSkippedLanes = mergeLanes(lane, workInProgressRootSkippedLanes);851 }852 function renderDidSuspend() {853 if (workInProgressRootExitStatus === RootIncomplete) {854 workInProgressRootExitStatus = RootSuspended;855 }856 }857 function renderDidSuspendDelayIfPossible() {858 if (workInProgressRootExitStatus === RootIncomplete || workInProgressRootExitStatus === RootSuspended) {859 workInProgressRootExitStatus = RootSuspendedWithDelay;860 } // Check if there are updates that we skipped tree that might have unblocked861 // this render.862 if (workInProgressRoot !== null && (includesNonIdleWork(workInProgressRootSkippedLanes) || includesNonIdleWork(workInProgressRootUpdatedLanes))) {863 // Mark the current render as suspended so that we switch to working on864 // the updates that were skipped. Usually we only suspend at the end of865 // the render phase.866 // TODO: We should probably always mark the root as suspended immediately867 // (inside this function), since by suspending at the end of the render868 // phase introduces a potential mistake where we suspend lanes that were869 // pinged or updated while we were rendering.870 markRootSuspended$1(workInProgressRoot, workInProgressRootRenderLanes);871 }872 }873 function renderDidError() {874 if (workInProgressRootExitStatus !== RootCompleted) {875 workInProgressRootExitStatus = RootErrored;876 }877 } // Called during render to determine if anything has suspended.878 // Returns false if we're not sure.879 function renderHasNotSuspendedYet() {880 // If something errored or completed, we can't really be sure,881 // so those are false.882 return workInProgressRootExitStatus === RootIncomplete;883 }884 function renderRootSync(root, lanes) {885 var prevExecutionContext = executionContext;886 executionContext |= RenderContext;887 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack888 // and prepare a fresh one. Otherwise we'll continue where we left off.889 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {890 prepareFreshStack(root, lanes);891 startWorkOnPendingInteractions(root, lanes);892 }893 var prevInteractions = pushInteractions(root);894 {895 markRenderStarted(lanes);896 }897 do {898 try {899 workLoopSync();900 break;901 } catch (thrownValue) {902 handleError(root, thrownValue);903 }904 } while (true);905 resetContextDependencies();906 {907 popInteractions(prevInteractions);908 }909 executionContext = prevExecutionContext;910 popDispatcher(prevDispatcher);911 if (workInProgress !== null) {912 // This is a sync render, so we should have finished the whole tree.913 {914 {915 throw Error( "Cannot commit an incomplete root. This error is likely caused by a bug in React. Please file an issue." );916 }917 }918 }919 {920 markRenderStopped();921 } // Set this to null to indicate there's no in-progress render.922 workInProgressRoot = null;923 workInProgressRootRenderLanes = NoLanes;924 return workInProgressRootExitStatus;925 } // The work loop is an extremely hot path. Tell Closure not to inline it.926 /** @noinline */927 function workLoopSync() {928 // Already timed out, so perform work without checking if we need to yield.929 while (workInProgress !== null) {930 performUnitOfWork(workInProgress);931 }932 }933 function renderRootConcurrent(root, lanes) {934 var prevExecutionContext = executionContext;935 executionContext |= RenderContext;936 var prevDispatcher = pushDispatcher(); // If the root or lanes have changed, throw out the existing stack937 // and prepare a fresh one. Otherwise we'll continue where we left off.938 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {939 resetRenderTimer();940 prepareFreshStack(root, lanes);941 startWorkOnPendingInteractions(root, lanes);942 }943 var prevInteractions = pushInteractions(root);944 {945 markRenderStarted(lanes);946 }947 do {948 try {949 workLoopConcurrent();950 break;951 } catch (thrownValue) {952 handleError(root, thrownValue);953 }954 } while (true);955 resetContextDependencies();956 {957 popInteractions(prevInteractions);958 }959 popDispatcher(prevDispatcher);960 executionContext = prevExecutionContext;961 if (workInProgress !== null) {962 // Still work remaining.963 {964 markRenderYielded();965 }966 return RootIncomplete;967 } else {968 // Completed the tree.969 {970 markRenderStopped();971 } // Set this to null to indicate there's no in-progress render.972 workInProgressRoot = null;973 workInProgressRootRenderLanes = NoLanes; // Return the final exit status.974 return workInProgressRootExitStatus;975 }976 }977 /** @noinline */978 function workLoopConcurrent() {979 // Perform work until Scheduler asks us to yield980 while (workInProgress !== null && !shouldYield()) {981 performUnitOfWork(workInProgress);982 }983 }984 function performUnitOfWork(unitOfWork) {985 // The current, flushed, state of this fiber is the alternate. Ideally986 // nothing should rely on this, but relying on it here means that we don't987 // need an additional field on the work in progress.988 var current = unitOfWork.alternate;989 setCurrentFiber(unitOfWork);990 var next;991 if ( (unitOfWork.mode & ProfileMode) !== NoMode) {992 startProfilerTimer(unitOfWork);993 next = beginWork$1(current, unitOfWork, subtreeRenderLanes);994 stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);995 } else {996 next = beginWork$1(current, unitOfWork, subtreeRenderLanes);997 }998 resetCurrentFiber();999 unitOfWork.memoizedProps = unitOfWork.pendingProps;1000 if (next === null) {1001 // If this doesn't spawn new work, complete the current work.1002 completeUnitOfWork(unitOfWork);1003 } else {1004 workInProgress = next;1005 }1006 ReactCurrentOwner$2.current = null;1007 }1008 function completeUnitOfWork(unitOfWork) {1009 // Attempt to complete the current unit of work, then move to the next1010 // sibling. If there are no more siblings, return to the parent fiber.1011 var completedWork = unitOfWork;1012 do {1013 // The current, flushed, state of this fiber is the alternate. Ideally1014 // nothing should rely on this, but relying on it here means that we don't1015 // need an additional field on the work in progress.1016 var current = completedWork.alternate;1017 var returnFiber = completedWork.return; // Check if the work completed or if something threw.1018 if ((completedWork.flags & Incomplete) === NoFlags) {1019 setCurrentFiber(completedWork);1020 var next = void 0;1021 if ( (completedWork.mode & ProfileMode) === NoMode) {1022 next = completeWork(current, completedWork, subtreeRenderLanes);1023 } else {1024 startProfilerTimer(completedWork);1025 next = completeWork(current, completedWork, subtreeRenderLanes); // Update render duration assuming we didn't error.1026 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);1027 }1028 resetCurrentFiber();1029 if (next !== null) {1030 // Completing this fiber spawned new work. Work on that next.1031 workInProgress = next;1032 return;1033 }1034 resetChildLanes(completedWork);1035 if (returnFiber !== null && // Do not append effects to parents if a sibling failed to complete1036 (returnFiber.flags & Incomplete) === NoFlags) {1037 // Append all the effects of the subtree and this fiber onto the effect1038 // list of the parent. The completion order of the children affects the1039 // side-effect order.1040 if (returnFiber.firstEffect === null) {1041 returnFiber.firstEffect = completedWork.firstEffect;1042 }1043 if (completedWork.lastEffect !== null) {1044 if (returnFiber.lastEffect !== null) {1045 returnFiber.lastEffect.nextEffect = completedWork.firstEffect;1046 }1047 returnFiber.lastEffect = completedWork.lastEffect;1048 } // If this fiber had side-effects, we append it AFTER the children's1049 // side-effects. We can perform certain side-effects earlier if needed,1050 // by doing multiple passes over the effect list. We don't want to1051 // schedule our own side-effect on our own list because if end up1052 // reusing children we'll schedule this effect onto itself since we're1053 // at the end.1054 var flags = completedWork.flags; // Skip both NoWork and PerformedWork tags when creating the effect1055 // list. PerformedWork effect is read by React DevTools but shouldn't be1056 // committed.1057 if (flags > PerformedWork) {1058 if (returnFiber.lastEffect !== null) {1059 returnFiber.lastEffect.nextEffect = completedWork;1060 } else {1061 returnFiber.firstEffect = completedWork;1062 }1063 returnFiber.lastEffect = completedWork;1064 }1065 }1066 } else {1067 // This fiber did not complete because something threw. Pop values off1068 // the stack without entering the complete phase. If this is a boundary,1069 // capture values if possible.1070 var _next = unwindWork(completedWork); // Because this fiber did not complete, don't reset its expiration time.1071 if (_next !== null) {1072 // If completing this work spawned new work, do that next. We'll come1073 // back here again.1074 // Since we're restarting, remove anything that is not a host effect1075 // from the effect tag.1076 _next.flags &= HostEffectMask;1077 workInProgress = _next;1078 return;1079 }1080 if ( (completedWork.mode & ProfileMode) !== NoMode) {1081 // Record the render duration for the fiber that errored.1082 stopProfilerTimerIfRunningAndRecordDelta(completedWork, false); // Include the time spent working on failed children before continuing.1083 var actualDuration = completedWork.actualDuration;1084 var child = completedWork.child;1085 while (child !== null) {1086 actualDuration += child.actualDuration;1087 child = child.sibling;1088 }1089 completedWork.actualDuration = actualDuration;1090 }1091 if (returnFiber !== null) {1092 // Mark the parent fiber as incomplete and clear its effect list.1093 returnFiber.firstEffect = returnFiber.lastEffect = null;1094 returnFiber.flags |= Incomplete;1095 }1096 }1097 var siblingFiber = completedWork.sibling;1098 if (siblingFiber !== null) {1099 // If there is more work to do in this returnFiber, do that next.1100 workInProgress = siblingFiber;1101 return;1102 } // Otherwise, return to the parent1103 completedWork = returnFiber; // Update the next thing we're working on in case something throws.1104 workInProgress = completedWork;1105 } while (completedWork !== null); // We've reached the root.1106 if (workInProgressRootExitStatus === RootIncomplete) {1107 workInProgressRootExitStatus = RootCompleted;1108 }1109 }1110 function resetChildLanes(completedWork) {1111 if ( // TODO: Move this check out of the hot path by moving `resetChildLanes`1112 // to switch statement in `completeWork`.1113 (completedWork.tag === LegacyHiddenComponent || completedWork.tag === OffscreenComponent) && completedWork.memoizedState !== null && !includesSomeLane(subtreeRenderLanes, OffscreenLane) && (completedWork.mode & ConcurrentMode) !== NoLanes) {1114 // The children of this component are hidden. Don't bubble their1115 // expiration times.1116 return;1117 }1118 var newChildLanes = NoLanes; // Bubble up the earliest expiration time.1119 if ( (completedWork.mode & ProfileMode) !== NoMode) {1120 // In profiling mode, resetChildExpirationTime is also used to reset1121 // profiler durations.1122 var actualDuration = completedWork.actualDuration;1123 var treeBaseDuration = completedWork.selfBaseDuration; // When a fiber is cloned, its actualDuration is reset to 0. This value will1124 // only be updated if work is done on the fiber (i.e. it doesn't bailout).1125 // When work is done, it should bubble to the parent's actualDuration. If1126 // the fiber has not been cloned though, (meaning no work was done), then1127 // this value will reflect the amount of time spent working on a previous1128 // render. In that case it should not bubble. We determine whether it was1129 // cloned by comparing the child pointer.1130 var shouldBubbleActualDurations = completedWork.alternate === null || completedWork.child !== completedWork.alternate.child;1131 var child = completedWork.child;1132 while (child !== null) {1133 newChildLanes = mergeLanes(newChildLanes, mergeLanes(child.lanes, child.childLanes));1134 if (shouldBubbleActualDurations) {1135 actualDuration += child.actualDuration;1136 }1137 treeBaseDuration += child.treeBaseDuration;1138 child = child.sibling;1139 }1140 var isTimedOutSuspense = completedWork.tag === SuspenseComponent && completedWork.memoizedState !== null;1141 if (isTimedOutSuspense) {1142 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1143 var primaryChildFragment = completedWork.child;1144 if (primaryChildFragment !== null) {1145 treeBaseDuration -= primaryChildFragment.treeBaseDuration;1146 }1147 }1148 completedWork.actualDuration = actualDuration;1149 completedWork.treeBaseDuration = treeBaseDuration;1150 } else {1151 var _child = completedWork.child;1152 while (_child !== null) {1153 newChildLanes = mergeLanes(newChildLanes, mergeLanes(_child.lanes, _child.childLanes));1154 _child = _child.sibling;1155 }1156 }1157 completedWork.childLanes = newChildLanes;1158 }1159 function commitRoot(root) {1160 var renderPriorityLevel = getCurrentPriorityLevel();1161 runWithPriority$1(ImmediatePriority$1, commitRootImpl.bind(null, root, renderPriorityLevel));1162 return null;1163 }1164 function commitRootImpl(root, renderPriorityLevel) {1165 do {1166 // `flushPassiveEffects` will call `flushSyncUpdateQueue` at the end, which1167 // means `flushPassiveEffects` will sometimes result in additional1168 // passive effects. So we need to keep flushing in a loop until there are1169 // no more pending effects.1170 // TODO: Might be better if `flushPassiveEffects` did not automatically1171 // flush synchronous work at the end, to avoid factoring hazards like this.1172 flushPassiveEffects();1173 } while (rootWithPendingPassiveEffects !== null);1174 flushRenderPhaseStrictModeWarningsInDEV();1175 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1176 {1177 throw Error( "Should not already be working." );1178 }1179 }1180 var finishedWork = root.finishedWork;1181 var lanes = root.finishedLanes;1182 {1183 markCommitStarted(lanes);1184 }1185 if (finishedWork === null) {1186 {1187 markCommitStopped();1188 }1189 return null;1190 }1191 root.finishedWork = null;1192 root.finishedLanes = NoLanes;1193 if (!(finishedWork !== root.current)) {1194 {1195 throw Error( "Cannot commit the same tree as before. This error is likely caused by a bug in React. Please file an issue." );1196 }1197 } // commitRoot never returns a continuation; it always finishes synchronously.1198 // So we can clear these now to allow a new callback to be scheduled.1199 root.callbackNode = null; // Update the first and last pending times on this root. The new first1200 // pending time is whatever is left on the root fiber.1201 var remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);1202 markRootFinished(root, remainingLanes); // Clear already finished discrete updates in case that a later call of1203 // `flushDiscreteUpdates` starts a useless render pass which may cancels1204 // a scheduled timeout.1205 if (rootsWithPendingDiscreteUpdates !== null) {1206 if (!hasDiscreteLanes(remainingLanes) && rootsWithPendingDiscreteUpdates.has(root)) {1207 rootsWithPendingDiscreteUpdates.delete(root);1208 }1209 }1210 if (root === workInProgressRoot) {1211 // We can reset these now that they are finished.1212 workInProgressRoot = null;1213 workInProgress = null;1214 workInProgressRootRenderLanes = NoLanes;1215 } // Get the list of effects.1216 var firstEffect;1217 if (finishedWork.flags > PerformedWork) {1218 // A fiber's effect list consists only of its children, not itself. So if1219 // the root has an effect, we need to add it to the end of the list. The1220 // resulting list is the set that would belong to the root's parent, if it1221 // had one; that is, all the effects in the tree including the root.1222 if (finishedWork.lastEffect !== null) {1223 finishedWork.lastEffect.nextEffect = finishedWork;1224 firstEffect = finishedWork.firstEffect;1225 } else {1226 firstEffect = finishedWork;1227 }1228 } else {1229 // There is no effect on the root.1230 firstEffect = finishedWork.firstEffect;1231 }1232 if (firstEffect !== null) {1233 var prevExecutionContext = executionContext;1234 executionContext |= CommitContext;1235 var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles1236 ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass1237 // of the effect list for each phase: all mutation effects come before all1238 // layout effects, and so on.1239 // The first phase a "before mutation" phase. We use this phase to read the1240 // state of the host tree right before we mutate it. This is where1241 // getSnapshotBeforeUpdate is called.1242 focusedInstanceHandle = prepareForCommit(root.containerInfo);1243 shouldFireAfterActiveInstanceBlur = false;1244 nextEffect = firstEffect;1245 do {1246 {1247 invokeGuardedCallback(null, commitBeforeMutationEffects, null);1248 if (hasCaughtError()) {1249 if (!(nextEffect !== null)) {1250 {1251 throw Error( "Should be working on an effect." );1252 }1253 }1254 var error = clearCaughtError();1255 captureCommitPhaseError(nextEffect, error);1256 nextEffect = nextEffect.nextEffect;1257 }1258 }1259 } while (nextEffect !== null); // We no longer need to track the active instance fiber1260 focusedInstanceHandle = null;1261 {1262 // Mark the current commit time to be shared by all Profilers in this1263 // batch. This enables them to be grouped later.1264 recordCommitTime();1265 } // The next phase is the mutation phase, where we mutate the host tree.1266 nextEffect = firstEffect;1267 do {1268 {1269 invokeGuardedCallback(null, commitMutationEffects, null, root, renderPriorityLevel);1270 if (hasCaughtError()) {1271 if (!(nextEffect !== null)) {1272 {1273 throw Error( "Should be working on an effect." );1274 }1275 }1276 var _error = clearCaughtError();1277 captureCommitPhaseError(nextEffect, _error);1278 nextEffect = nextEffect.nextEffect;1279 }1280 }1281 } while (nextEffect !== null);1282 resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after1283 // the mutation phase, so that the previous tree is still current during1284 // componentWillUnmount, but before the layout phase, so that the finished1285 // work is current during componentDidMount/Update.1286 root.current = finishedWork; // The next phase is the layout phase, where we call effects that read1287 // the host tree after it's been mutated. The idiomatic use case for this is1288 // layout, but class component lifecycles also fire here for legacy reasons.1289 nextEffect = firstEffect;1290 do {1291 {1292 invokeGuardedCallback(null, commitLayoutEffects, null, root, lanes);1293 if (hasCaughtError()) {1294 if (!(nextEffect !== null)) {1295 {1296 throw Error( "Should be working on an effect." );1297 }1298 }1299 var _error2 = clearCaughtError();1300 captureCommitPhaseError(nextEffect, _error2);1301 nextEffect = nextEffect.nextEffect;1302 }1303 }1304 } while (nextEffect !== null);1305 nextEffect = null; // Tell Scheduler to yield at the end of the frame, so the browser has an1306 // opportunity to paint.1307 requestPaint();1308 {1309 popInteractions(prevInteractions);1310 }1311 executionContext = prevExecutionContext;1312 } else {1313 // No effects.1314 root.current = finishedWork; // Measure these anyway so the flamegraph explicitly shows that there were1315 // no effects.1316 // TODO: Maybe there's a better way to report this.1317 {1318 recordCommitTime();1319 }1320 }1321 var rootDidHavePassiveEffects = rootDoesHavePassiveEffects;1322 if (rootDoesHavePassiveEffects) {1323 // This commit has passive effects. Stash a reference to them. But don't1324 // schedule a callback until after flushing layout work.1325 rootDoesHavePassiveEffects = false;1326 rootWithPendingPassiveEffects = root;1327 pendingPassiveEffectsLanes = lanes;1328 pendingPassiveEffectsRenderPriority = renderPriorityLevel;1329 } else {1330 // We are done with the effect chain at this point so let's clear the1331 // nextEffect pointers to assist with GC. If we have passive effects, we'll1332 // clear this in flushPassiveEffects.1333 nextEffect = firstEffect;1334 while (nextEffect !== null) {1335 var nextNextEffect = nextEffect.nextEffect;1336 nextEffect.nextEffect = null;1337 if (nextEffect.flags & Deletion) {1338 detachFiberAfterEffects(nextEffect);1339 }1340 nextEffect = nextNextEffect;1341 }1342 } // Read this again, since an effect might have updated it1343 remainingLanes = root.pendingLanes; // Check if there's remaining work on this root1344 if (remainingLanes !== NoLanes) {1345 {1346 if (spawnedWorkDuringRender !== null) {1347 var expirationTimes = spawnedWorkDuringRender;1348 spawnedWorkDuringRender = null;1349 for (var i = 0; i < expirationTimes.length; i++) {1350 scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);1351 }1352 }1353 schedulePendingInteractions(root, remainingLanes);1354 }1355 } else {1356 // If there's no remaining work, we can clear the set of already failed1357 // error boundaries.1358 legacyErrorBoundariesThatAlreadyFailed = null;1359 }1360 {1361 if (!rootDidHavePassiveEffects) {1362 // If there are no passive effects, then we can complete the pending interactions.1363 // Otherwise, we'll wait until after the passive effects are flushed.1364 // Wait to do this until after remaining work has been scheduled,1365 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1366 finishPendingInteractions(root, lanes);1367 }1368 }1369 if (remainingLanes === SyncLane) {1370 // Count the number of times the root synchronously re-renders without1371 // finishing. If there are too many, it indicates an infinite update loop.1372 if (root === rootWithNestedUpdates) {1373 nestedUpdateCount++;1374 } else {1375 nestedUpdateCount = 0;1376 rootWithNestedUpdates = root;1377 }1378 } else {1379 nestedUpdateCount = 0;1380 }1381 onCommitRoot(finishedWork.stateNode, renderPriorityLevel);1382 {1383 onCommitRoot$1();1384 } // Always call this before exiting `commitRoot`, to ensure that any1385 // additional work on this root is scheduled.1386 ensureRootIsScheduled(root, now());1387 if (hasUncaughtError) {1388 hasUncaughtError = false;1389 var _error3 = firstUncaughtError;1390 firstUncaughtError = null;1391 throw _error3;1392 }1393 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1394 {1395 markCommitStopped();1396 } // This is a legacy edge case. We just committed the initial mount of1397 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1398 // synchronously, but layout updates should be deferred until the end1399 // of the batch.1400 return null;1401 } // If layout work was scheduled, flush it now.1402 flushSyncCallbackQueue();1403 {1404 markCommitStopped();1405 }1406 return null;1407 }1408 function commitBeforeMutationEffects() {1409 while (nextEffect !== null) {1410 var current = nextEffect.alternate;1411 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1412 if ((nextEffect.flags & Deletion) !== NoFlags) {1413 if (doesFiberContain(nextEffect, focusedInstanceHandle)) {1414 shouldFireAfterActiveInstanceBlur = true;1415 }1416 } else {1417 // TODO: Move this out of the hot path using a dedicated effect tag.1418 if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {1419 shouldFireAfterActiveInstanceBlur = true;1420 }1421 }1422 }1423 var flags = nextEffect.flags;1424 if ((flags & Snapshot) !== NoFlags) {1425 setCurrentFiber(nextEffect);1426 commitBeforeMutationLifeCycles(current, nextEffect);1427 resetCurrentFiber();1428 }1429 if ((flags & Passive) !== NoFlags) {1430 // If there are passive effects, schedule a callback to flush at1431 // the earliest opportunity.1432 if (!rootDoesHavePassiveEffects) {1433 rootDoesHavePassiveEffects = true;1434 scheduleCallback(NormalPriority$1, function () {1435 flushPassiveEffects();1436 return null;1437 });1438 }1439 }1440 nextEffect = nextEffect.nextEffect;1441 }1442 }1443 function commitMutationEffects(root, renderPriorityLevel) {1444 // TODO: Should probably move the bulk of this function to commitWork.1445 while (nextEffect !== null) {1446 setCurrentFiber(nextEffect);1447 var flags = nextEffect.flags;1448 if (flags & ContentReset) {1449 commitResetTextContent(nextEffect);1450 }1451 if (flags & Ref) {1452 var current = nextEffect.alternate;1453 if (current !== null) {1454 commitDetachRef(current);1455 }1456 } // The following switch statement is only concerned about placement,1457 // updates, and deletions. To avoid needing to add a case for every possible1458 // bitmap value, we remove the secondary effects from the effect tag and1459 // switch on that value.1460 var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);1461 switch (primaryFlags) {1462 case Placement:1463 {1464 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1465 // inserted, before any life-cycles like componentDidMount gets called.1466 // TODO: findDOMNode doesn't rely on this any more but isMounted does1467 // and isMounted is deprecated anyway so we should be able to kill this.1468 nextEffect.flags &= ~Placement;1469 break;1470 }1471 case PlacementAndUpdate:1472 {1473 // Placement1474 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1475 // inserted, before any life-cycles like componentDidMount gets called.1476 nextEffect.flags &= ~Placement; // Update1477 var _current = nextEffect.alternate;1478 commitWork(_current, nextEffect);1479 break;1480 }1481 case Hydrating:1482 {1483 nextEffect.flags &= ~Hydrating;1484 break;1485 }1486 case HydratingAndUpdate:1487 {1488 nextEffect.flags &= ~Hydrating; // Update1489 var _current2 = nextEffect.alternate;1490 commitWork(_current2, nextEffect);1491 break;1492 }1493 case Update:1494 {1495 var _current3 = nextEffect.alternate;1496 commitWork(_current3, nextEffect);1497 break;1498 }1499 case Deletion:1500 {1501 commitDeletion(root, nextEffect);1502 break;1503 }1504 }1505 resetCurrentFiber();1506 nextEffect = nextEffect.nextEffect;1507 }1508 }1509 function commitLayoutEffects(root, committedLanes) {1510 {1511 markLayoutEffectsStarted(committedLanes);1512 } // TODO: Should probably move the bulk of this function to commitWork.1513 while (nextEffect !== null) {1514 setCurrentFiber(nextEffect);1515 var flags = nextEffect.flags;1516 if (flags & (Update | Callback)) {1517 var current = nextEffect.alternate;1518 commitLifeCycles(root, current, nextEffect);1519 }1520 {1521 if (flags & Ref) {1522 commitAttachRef(nextEffect);1523 }1524 }1525 resetCurrentFiber();1526 nextEffect = nextEffect.nextEffect;1527 }1528 {1529 markLayoutEffectsStopped();1530 }1531 }1532 function flushPassiveEffects() {1533 // Returns whether passive effects were flushed.1534 if (pendingPassiveEffectsRenderPriority !== NoPriority$1) {1535 var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority$1 ? NormalPriority$1 : pendingPassiveEffectsRenderPriority;1536 pendingPassiveEffectsRenderPriority = NoPriority$1;1537 {1538 return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);1539 }1540 }1541 return false;1542 }1543 function enqueuePendingPassiveHookEffectMount(fiber, effect) {1544 pendingPassiveHookEffectsMount.push(effect, fiber);1545 if (!rootDoesHavePassiveEffects) {1546 rootDoesHavePassiveEffects = true;1547 scheduleCallback(NormalPriority$1, function () {1548 flushPassiveEffects();1549 return null;1550 });1551 }1552 }1553 function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {1554 pendingPassiveHookEffectsUnmount.push(effect, fiber);1555 {1556 fiber.flags |= PassiveUnmountPendingDev;1557 var alternate = fiber.alternate;1558 if (alternate !== null) {1559 alternate.flags |= PassiveUnmountPendingDev;1560 }1561 }1562 if (!rootDoesHavePassiveEffects) {1563 rootDoesHavePassiveEffects = true;1564 scheduleCallback(NormalPriority$1, function () {1565 flushPassiveEffects();1566 return null;1567 });1568 }1569 }1570 function invokePassiveEffectCreate(effect) {1571 var create = effect.create;1572 effect.destroy = create();1573 }1574 function flushPassiveEffectsImpl() {1575 if (rootWithPendingPassiveEffects === null) {1576 return false;1577 }1578 var root = rootWithPendingPassiveEffects;1579 var lanes = pendingPassiveEffectsLanes;1580 rootWithPendingPassiveEffects = null;1581 pendingPassiveEffectsLanes = NoLanes;1582 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1583 {1584 throw Error( "Cannot flush passive effects while already rendering." );1585 }1586 }1587 {1588 markPassiveEffectsStarted(lanes);1589 }1590 {1591 isFlushingPassiveEffects = true;1592 }1593 var prevExecutionContext = executionContext;1594 executionContext |= CommitContext;1595 var prevInteractions = pushInteractions(root); // It's important that ALL pending passive effect destroy functions are called1596 // before ANY passive effect create functions are called.1597 // Otherwise effects in sibling components might interfere with each other.1598 // e.g. a destroy function in one component may unintentionally override a ref1599 // value set by a create function in another component.1600 // Layout effects have the same constraint.1601 // First pass: Destroy stale passive effects.1602 var unmountEffects = pendingPassiveHookEffectsUnmount;1603 pendingPassiveHookEffectsUnmount = [];1604 for (var i = 0; i < unmountEffects.length; i += 2) {1605 var _effect = unmountEffects[i];1606 var fiber = unmountEffects[i + 1];1607 var destroy = _effect.destroy;1608 _effect.destroy = undefined;1609 {...
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js
...425 rootWithPendingPassiveEffects = null;426 pendingPassiveEffectsLanes = NoLanes;427 const prevExecutionContext = executionContext;428 executionContext |= CommitContext;429 const prevInteractions = pushInteractions(root);430 commitPassiveUnmountEffects(root.current);431 commitPassiveMountEffects(root, root.current);432 executionContext = prevExecutionContext;433 flushSyncCallbackQueue();434 // If additional passive effects were scheduled, increment a counter. If this435 // exceeds the limit, we'll fire a warning.436 nestedPassiveUpdateCount =437 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;438 return true;439}440function pushInteractions(root) {441 // if (enableSchedulerTracing) {442 // const prevInteractions = __interactionsRef.current;443 // __interactionsRef.current = root.memoizedInteractions;444 // return prevInteractions;445 // }446 return null;447}448// This is split into a separate function so we can mark a fiber with pending449// work without treating it as a typical update that originates from an event;450// e.g. retrying a Suspense boundary isn't an update, but it does schedule work451// on a fiber.452function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {453 // Update the source fiber's lanes454 sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);455 let alternate = sourceFiber.alternate;456 if (alternate !== null) {457 alternate.lanes = mergeLanes(alternate.lanes, lane);458 }459 // Walk the parent path to the root and update the child expiration time.460 let node = sourceFiber;461 let parent = sourceFiber.return;462 while (parent !== null) {463 parent.childLanes = mergeLanes(parent.childLanes, lane);464 alternate = parent.alternate;465 if (alternate !== null) {466 alternate.childLanes = mergeLanes(alternate.childLanes, lane);467 }468 node = parent;469 parent = parent.return;470 }471 if (node.tag === HostRoot) {472 const root = node.stateNode;473 return root;474 } else {475 return null;476 }477}478function pushDispatcher() {479 // const prevDispatcher = ReactCurrentDispatcher.current;480}481function popDispatcher(prevDispatcher) {}482function renderRootSync(root, lanes) {483 const prevExecutionContext = executionContext;484 executionContext |= RenderContext;485 // const prevDispatcher = pushDispatcher();486 // If the root or lanes have changed, throw out the existing stack487 // and prepare a fresh one. Otherwise we'll continue where we left off.488 if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {489 prepareFreshStack(root, lanes);490 // startWorkOnPendingInteractions(root, lanes);491 }492 // const prevInteractions = pushInteractions(root);493 do {494 try {495 workLoopSync();496 break;497 } catch (thrownValue) {498 handleError(root, thrownValue);499 }500 } while (true);501 // resetContextDependencies();502 executionContext = prevExecutionContext;503 // popDispatcher(prevDispatcher);504 if (workInProgress !== null) {505 // This is a sync render, so we should have finished the whole tree.506 console.error(...
4 - commitWork.js
Source:4 - commitWork.js
...100 const previousPriority = getCurrentUpdatePriority();101 setCurrentUpdatePriority(DiscreteEventPriority);102 const prevExecutionContext = executionContext;103 executionContext |= CommitContext;104 const prevInteractions = pushInteractions(root);105 // Reset this to null before calling lifecycles106 ReactCurrentOwner.current = null;107 // The commit phase is broken into several sub-phases. We do a separate pass108 // of the effect list for each phase: all mutation effects come before all109 // layout effects, and so on.110 // The first phase a "before mutation" phase. We use this phase to read the111 // state of the host tree right before we mutate it. This is where112 // getSnapshotBeforeUpdate is called.113 const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(114 root,115 finishedWork,116 );117 if (enableProfilerTimer) {118 // Mark the current commit time to be shared by all Profilers in this119 // batch. This enables them to be grouped later.120 recordCommitTime();121 }122 if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {123 // Track the root here, rather than in commitLayoutEffects(), because of ref setters.124 // Updates scheduled during ref detachment should also be flagged.125 rootCommittingMutationOrLayoutEffects = root;126 }127 // The next phase is the mutation phase, where we mutate the host tree.128 commitMutationEffects(root, finishedWork);129 if (shouldFireAfterActiveInstanceBlur) {130 afterActiveInstanceBlur();131 }132 resetAfterCommit(root.containerInfo);133 // The work-in-progress tree is now the current tree. This must come after134 // the mutation phase, so that the previous tree is still current during135 // componentWillUnmount, but before the layout phase, so that the finished136 // work is current during componentDidMount/Update.137 root.current = finishedWork;138 // The next phase is the layout phase, where we call effects that read139 // the host tree after it's been mutated. The idiomatic use case for this is140 // layout, but class component lifecycles also fire here for legacy reasons.141 if (enableSchedulingProfiler) {142 markLayoutEffectsStarted(lanes);143 }144 commitLayoutEffects(finishedWork, root, lanes);145 if (enableSchedulingProfiler) {146 markLayoutEffectsStopped();147 }148 if (enableProfilerTimer && enableProfilerNestedUpdateScheduledHook) {149 rootCommittingMutationOrLayoutEffects = null;150 }151 // Tell Scheduler to yield at the end of the frame, so the browser has an152 // opportunity to paint.153 requestPaint();154 if (enableSchedulerTracing) {155 popInteractions(((prevInteractions: any): Set<Interaction>));156 }157 executionContext = prevExecutionContext;158 // Reset the priority to the previous non-sync value.159 setCurrentUpdatePriority(previousPriority);160 ReactCurrentBatchConfig.transition = prevTransition;161 } else {162 // No effects.163 root.current = finishedWork;164 // Measure these anyway so the flamegraph explicitly shows that there were165 // no effects.166 // TODO: Maybe there's a better way to report this.167 if (enableProfilerTimer) {168 recordCommitTime();169 }170 }171 const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;172 if (rootDoesHavePassiveEffects) {173 // This commit has passive effects. Stash a reference to them. But don't174 // schedule a callback until after flushing layout work.175 rootDoesHavePassiveEffects = false;176 rootWithPendingPassiveEffects = root;177 pendingPassiveEffectsLanes = lanes;178 }179 // Read this again, since an effect might have updated it180 remainingLanes = root.pendingLanes;181 // Check if there's remaining work on this root182 if (remainingLanes !== NoLanes) {183 if (enableSchedulerTracing) {184 if (spawnedWorkDuringRender !== null) {185 const expirationTimes = spawnedWorkDuringRender;186 spawnedWorkDuringRender = null;187 for (let i = 0; i < expirationTimes.length; i++) {188 scheduleInteractions(189 root,190 expirationTimes[i],191 root.memoizedInteractions,192 );193 }194 }195 schedulePendingInteractions(root, remainingLanes);196 }197 } else {198 // If there's no remaining work, we can clear the set of already failed199 // error boundaries.200 legacyErrorBoundariesThatAlreadyFailed = null;201 }202 if (enableSchedulerTracing) {203 if (!rootDidHavePassiveEffects) {204 // If there are no passive effects, then we can complete the pending interactions.205 // Otherwise, we'll wait until after the passive effects are flushed.206 // Wait to do this until after remaining work has been scheduled,207 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.208 finishPendingInteractions(root, lanes);209 }210 }211 if (includesSomeLane(remainingLanes, (SyncLane: Lane))) {212 if (enableProfilerTimer && enableProfilerNestedUpdatePhase) {213 markNestedUpdateScheduled();214 }215 // Count the number of times the root synchronously re-renders without216 // finishing. If there are too many, it indicates an infinite update loop.217 if (root === rootWithNestedUpdates) {218 nestedUpdateCount++;219 } else {220 nestedUpdateCount = 0;221 rootWithNestedUpdates = root;222 }223 } else {224 nestedUpdateCount = 0;225 }226 onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);227 // Always call this before exiting `commitRoot`, to ensure that any228 // additional work on this root is scheduled.229 ensureRootIsScheduled(root, now());230 if (hasUncaughtError) {231 hasUncaughtError = false;232 const error = firstUncaughtError;233 firstUncaughtError = null;234 throw error;235 }236 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {237 if (enableSchedulingProfiler) {238 markCommitStopped();239 }240 // This is a legacy edge case. We just committed the initial mount of241 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired242 // synchronously, but layout updates should be deferred until the end243 // of the batch.244 return null;245 }246 // If the passive effects are the result of a discrete render, flush them247 // synchronously at the end of the current task so that the result is248 // immediately observable. Otherwise, we assume that they are not249 // order-dependent and do not need to be observed by external systems, so we250 // can wait until after paint.251 // TODO: We can optimize this by not scheduling the callback earlier. Since we252 // currently schedule the callback in multiple places, will wait until those253 // are consolidated.254 if (255 includesSomeLane(pendingPassiveEffectsLanes, SyncLane) &&256 root.tag !== LegacyRoot257 ) {258 flushPassiveEffects();259 }260 // If layout work was scheduled, flush it now.261 flushSyncCallbackQueue();262 if (enableSchedulingProfiler) {263 markCommitStopped();264 }265 return null;266}267export function flushPassiveEffects(): boolean {268 // Returns whether passive effects were flushed.269 if (pendingPassiveEffectsLanes !== NoLanes) {270 const priority = higherEventPriority(271 DefaultEventPriority,272 lanesToEventPriority(pendingPassiveEffectsLanes),273 );274 const prevTransition = ReactCurrentBatchConfig.transition;275 const previousPriority = getCurrentUpdatePriority();276 try {277 ReactCurrentBatchConfig.transition = 0;278 setCurrentUpdatePriority(priority);279 return flushPassiveEffectsImpl();280 } finally {281 setCurrentUpdatePriority(previousPriority);282 ReactCurrentBatchConfig.transition = prevTransition;283 }284 }285 return false;286}287function flushPassiveEffectsImpl() {288 if (rootWithPendingPassiveEffects === null) {289 return false;290 }291 const root = rootWithPendingPassiveEffects;292 const lanes = pendingPassiveEffectsLanes;293 rootWithPendingPassiveEffects = null;294 pendingPassiveEffectsLanes = NoLanes;295 invariant(296 (executionContext & (RenderContext | CommitContext)) === NoContext,297 'Cannot flush passive effects while already rendering.',298 );299 if (enableSchedulingProfiler) {300 markPassiveEffectsStarted(lanes);301 }302 const prevExecutionContext = executionContext;303 executionContext |= CommitContext;304 const prevInteractions = pushInteractions(root);305 commitPassiveUnmountEffects(root.current);306 commitPassiveMountEffects(root, root.current);307 // TODO: Move to commitPassiveMountEffects308 if (enableProfilerTimer && enableProfilerCommitHooks) {309 const profilerEffects = pendingPassiveProfilerEffects;310 pendingPassiveProfilerEffects = [];311 for (let i = 0; i < profilerEffects.length; i++) {312 const fiber = ((profilerEffects[i]: any): Fiber);313 commitPassiveEffectDurations(root, fiber);314 }315 }316 if (enableSchedulerTracing) {317 popInteractions(((prevInteractions: any): Set<Interaction>));318 finishPendingInteractions(root, lanes);...
commitRootImpl.js
Source:commitRootImpl.js
...58 }59 if (firstEffect !== null) {60 var prevExecutionContext = executionContext;61 executionContext |= CommitContext;62 var prevInteractions = pushInteractions(root); // Reset this to null before calling lifecycles63 ReactCurrentOwner$2.current = null; // The commit phase is broken into several sub-phases. We do a separate pass64 // of the effect list for each phase: all mutation effects come before all65 // layout effects, and so on.66 // The first phase a "before mutation" phase. We use this phase to read the67 // state of the host tree right before we mutate it. This is where68 // getSnapshotBeforeUpdate is called.69 startCommitSnapshotEffectsTimer();70 prepareForCommit(root.containerInfo);71 nextEffect = firstEffect;72 do {73 {74 invokeGuardedCallback(null, commitBeforeMutationEffects, null);75 if (hasCaughtError()) {76 (function () {...
finishSyncRender.js
Source:finishSyncRender.js
...41 }42 if (firstEffect !== null) {43 const prevExecutionContext = executionContext;44 executionContext |= CommitContext;45 const prevInteractions = pushInteractions(root);46 ReactCurrentOwner.current = null;47 startCommitSnapshotEffectsTimer();48 prepareForCommit(root.containerInfo);49 nextEffect = firstEffect;50 do {51 try {52 commitBeforeMutationEffects();53 } catch (error) {54 invariant(nextEffect !== null, 'Should be working on an effect.');55 captureCommitPhaseError(nextEffect, error);56 nextEffect = nextEffect.nextEffect;57 }58 } while (nextEffect !== null);59 stopCommitSnapshotEffectsTimer();...
flushPassiveEffectsImpl.js
Source:flushPassiveEffectsImpl.js
...14 }15 })();16 var prevExecutionContext = executionContext;17 executionContext |= CommitContext;18 var prevInteractions = pushInteractions(root); // Note: This currently assumes there are no passive effects on the root19 // fiber, because the root is not part of its own effect list. This could20 // change in the future.21 var effect = root.current.firstEffect;22 while (effect !== null) {23 {24 setCurrentFiber(effect);25 invokeGuardedCallback(null, commitPassiveHookEffects, null, effect);26 if (hasCaughtError()) {27 (function () {28 if (!(effect !== null)) {29 {30 throw ReactError(Error("Should be working on an effect."));31 }32 }...
StoryReal.js
Source:StoryReal.js
1import React from 'react';2import Story from "./story";3import './StoryReal.css';4function StoryReal() {5 return (6 <div className="storyReal">7 <Story profileSrc="https://avatars1.githubusercontent.com/u/25810173?s=460&u=75f18d14145fc8bb2c24cf15cb64d211793e42a5&v=4" image="https://www.pentasia.com/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXhwIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--9b531a296e23edbb0ae0d85e4160a44a71b44f8e/1662_original.jpg" title="Mohib Arsala" />8 <Story profileSrc="https://pbs.twimg.com/profile_images/1053717990171176962/rIDEHTl3_400x400.jpg" image="https://pushinteractions-collegemobileinc.netdna-ssl.com/wp-content/themes/PushInteractions/blogimages/12.jpg" title="Mohib Arsala" />9 <Story profileSrc="https://avatars1.githubusercontent.com/u/25810173?s=460&u=75f18d14145fc8bb2c24cf15cb64d211793e42a5&v=4" image="https://pushinteractions-collegemobileinc.netdna-ssl.com/wp-content/themes/PushInteractions/blogimages/12.jpg" title="Mohib Arsala" />10 <Story profileSrc="https://avatars1.githubusercontent.com/u/25810173?s=460&u=75f18d14145fc8bb2c24cf15cb64d211793e42a5&v=4" image="https://specials-images.forbesimg.com/imageserve/5f302109ffad89f9130e07db/960x0.jpg?cropX1=0&cropX2=4800&cropY1=243&cropY2=2943" title="Mohib Arsala" />11 <Story profileSrc="https://avatars1.githubusercontent.com/u/25810173?s=460&u=75f18d14145fc8bb2c24cf15cb64d211793e42a5&v=4" image="https://images.spot.im/v1/production/fl1o2a0z8voo6xoya1pb" title="Mohib Arsala" />12 </div>13 )14}...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.click('input[name="q"]');7 await page.keyboard.type('Hello World');8 await page.keyboard.press('Enter');9 await page.waitForNavigation();10 await page.screenshot({ path: 'google.png' });11 await browser.close();12})();13const { chromium } = require('playwright');14(async () => {15 const browser = await chromium.launch();16 const context = await browser.newContext();17 const page = await context.newPage();18 await page.click('input[name="q"]');19 await page.keyboard.type('Hello World');20 await page.keyboard.press('Enter');21 await page.waitForNavigation();22 await page.screenshot({ path: 'google.png' });23 await browser.close();24})();25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch();28 const context = await browser.newContext();29 const page = await context.newPage();30 await page.click('input[name="q"]');31 await page.keyboard.type('Hello World');32 await page.keyboard.press('Enter');33 await page.waitForNavigation();34 await page.screenshot({ path: 'google.png' });35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch();40 const context = await browser.newContext();41 const page = await context.newPage();42 await page.click('input[name="q"]');43 await page.keyboard.type('Hello World');44 await page.keyboard.press('Enter');45 await page.waitForNavigation();46 await page.screenshot({ path: 'google.png' });47 await browser.close();48})();49const { chromium } =
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.pushInteractions([7 {8 },9 ]);10 await page.screenshot({ path: 'example.png' });11 await browser.close();12})();13const { chromium } = require('playwright');14(async () => {15 const browser = await chromium.launch({ headless: false });16 const context = await browser.newContext();17 const page = await context.newPage();18 await page.pushInteractions([19 {20 },21 ]);22 await page.screenshot({ path: 'example.png' });23 await browser.close();24})();25const { chromium } = require('playwright');26(async () => {27 const browser = await chromium.launch({ headless: false });28 const context = await browser.newContext();29 const page = await context.newPage();30 await page.pushInteractions([31 {32 },33 ]);34 await page.screenshot({ path: 'example.png' });35 await browser.close();36})();37const { chromium } = require('playwright');38(async () => {39 const browser = await chromium.launch({ headless: false });40 const context = await browser.newContext();41 const page = await context.newPage();42 await page.pushInteractions([43 {44 },45 ]);46 await page.screenshot({ path: 'example.png' });47 await browser.close();48})();49const { chromium } =
Using AI Code Generation
1const { chromium } = require('playwright');2const fs = require('fs');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const interactions = JSON.parse(fs.readFileSync('interactions.json', 'utf8'));8 await page.pushInteractions(interactions);9 await page.screenshot({ path: 'screenshot.png' });10 await browser.close();11})();12const { chromium } = require('playwright');13const fs = require('fs');14(async () => {15 const browser = await chromium.launch();16 const context = await browser.newContext();17 const page = await context.newPage();18 await page.startTracing();19 await page.click('text=Get Started');20 const interactions = await page.stopTracing();21 fs.writeFileSync('interactions.json', JSON.stringify(interactions), 'utf8');22 await browser.close();23})();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 await page.pushInteractions([6 {7 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(1)',8 },9 {10 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(2)',11 },12 {13 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(3)',14 },15 ]);16 await browser.close();17})();18const { chromium } = require('playwright');19(async () => {20 const browser = await chromium.launch();21 const page = await browser.newPage();22 await page.pushInteractions([23 {24 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(1)',25 },26 {27 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(2)',28 },29 {30 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(3)',31 },32 ]);33 await browser.close();34})();35const { chromium } = require('playwright');36(async () => {37 const browser = await chromium.launch();38 const page = await browser.newPage();39 await page.pushInteractions([40 {41 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(1)',42 },43 {44 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(2)',45 },46 {47 selector: '#navbar > nav > div:nth-child(1) > a:nth-child(3)',48 },49 ]);50 await browser.close();51})();
Using AI Code Generation
1const { chromium } = require('playwright-core');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForSelector('input[name="q"]');7 await page.type('input[name="q"]', 'hello world');8 await page.keyboard.press('Enter');9 await page.waitForSelector('text="Hello World"');10 await page.click('text="Hello World"');11 await page.waitForSelector('text="Hello, World!"');12 await page.close();13 await context.close();14 await browser.close();15})();16const { chromium } = require('playwright-core');17(async () => {18 const browser = await chromium.launch();19 const context = await browser.newContext();20 const page = await context.newPage();21 await page.waitForSelector('input[name="q"]');22 await page.type('input[name="q"]', 'hello world');23 await page.keyboard.press('Enter');24 await page.waitForSelector('text="Hello World"');25 await page.click('text="Hello World"');26 await page.waitForSelector('text="Hello, World!"');27 await page.close();28 await context.close();29 await browser.close();30})();31const { chromium } = require('playwright-core');32(async () => {33 const browser = await chromium.launch();34 const context = await browser.newContext();35 const page = await context.newPage();36 await page.waitForSelector('input[name="q"]');37 await page.type('input[name="q"]', 'hello world');38 await page.keyboard.press('Enter');39 await page.waitForSelector('text="Hello World"');40 await page.click('text="Hello World"');41 await page.waitForSelector('text="Hello, World!"');42 await page.close();43 await context.close();44 await browser.close();45})();46const { chromium } = require('playwright-core');47(async () => {
Using AI Code Generation
1const { chromium } = require('playwright');2const { pushInteractions } = require('playwright/lib/internal/recorder/recorderActions');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await pushInteractions(page, [8 {9 position: { x: 0, y: 0 },10 },11 ]);12 await page.screenshot({ path: `example.png` });13 await browser.close();14})();15const { chromium } = require('playwright');16const { pushInteractions } = require('playwright/lib/internal/recorder/recorderActions');17(async () => {18 const browser = await chromium.launch();19 const context = await browser.newContext();20 const page = await context.newPage();21 await pushInteractions(page, [22 {23 position: { x: 0, y: 0 },24 },25 ]);26 await page.screenshot({ path: `example.png` });27 await browser.close();28})();29const { chromium } = require('playwright');30const { pushInteractions } = require('playwright/lib/internal/recorder/recorderActions');31(async () => {32 const browser = await chromium.launch();33 const context = await browser.newContext();34 const page = await context.newPage();35 await pushInteractions(page, [36 {37 position: { x: 0, y: 0 },38 },39 ]);40 await page.screenshot({ path: `example.png` });41 await browser.close();42})();43const {
Using AI Code Generation
1const { chromium } = require('playwright');2const { pushInteractions } = require('playwright/lib/internal/recorder/recorderActions');3const fs = require('fs');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 await page.click('input[name="q"]');9 await page.fill('input[name="q"]', 'Hello World');10 await page.press('input[name="q"]', 'Enter');11 const interactions = await pushInteractions();12 fs.writeFileSync('test.json', JSON.stringify(interactions));13 await browser.close();14})();15{16 {17 },18 {19 },20 {21 },22 {23 }24}25const { chromium } = require('playwright');26const { parseInteractions } = require('playwright/lib/internal/recorder/recorderActions');27const fs = require('fs');28(async () => {29 const browser = await chromium.launch();30 const context = await browser.newContext();31 const page = await context.newPage();32 const interactions = fs.readFileSync('test.json', 'utf8');33 await parseInteractions(page, JSON.parse(interactions));34 await browser.close();35})();36{37 {38 },39 {
Using AI Code Generation
1const { Playwright } = require('@playwright/test');2const { test, expect, it } = require('@playwright/test');3const { pushInteractions, popInteractions, clearInteractions, interactions } = require('@playwright/test');4const { chromium } = require('playwright');5test.describe('Playwright Internal API', () => {6 test.beforeAll(async ({browserName}) => {7 const browser = await chromium.launch();8 const context = await browser.newContext();9 const page = await context.newPage();10 await page.fill('input[name="q"]', 'Playwright');11 await page.click('input[value="Google Search"]');12 await page.waitForSelector('text=Playwright - Google Search');13 await page.click('text=Playwright - Google Search');14 console.log(interactions().length);15 console.log(interactions());16 clearInteractions();17 console.log(interactions().length);18 console.log(interactions());19 pushInteractions();20 console.log(interactions().length);21 console.log(interactions());22 popInteractions();23 console.log(interactions().length);24 console.log(interactions());25 });26 test('test', async ({page}) => {27 await page.fill('input[name="q"]', 'Playwright');28 await page.click('input[value="Google Search"]');29 await page.waitForSelector('text=Playwright - Google Search');30 await page.click('text=Playwright - Google Search');31 });32});33Your name to display (optional):34Your name to display (optional):35const { Playwright } = require('@playwright/test');36const { test, expect, it } = require('@playwright/test');
Using AI Code Generation
1await page.type('#my-input', 'Hello World');2await page.click('#my-button');3const { chromium } = require('playwright');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 await page.screenshot({ path: 'example.png' });9 await browser.close();10})();11const { chromium } = require('playwright');12(async () => {13 const browser = await chromium.launch();14 const context = await browser.newContext();15 const page = await context.newPage();16 await page.screenshot({ path: 'example.png' });17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 await page.screenshot({ path: 'example.png' });25 await browser.close();26})();27const { chromium } = require('playwright');28(async () => {29 const browser = await chromium.launch();30 const context = await browser.newContext();31 const page = await context.newPage();32 await page.screenshot({ path: 'example.png' });33 await browser.close();34})();35const { chromium } = require('playwright');36(async () => {37 const browser = await chromium.launch();38 const context = await browser.newContext();39 const page = await context.newPage();40 await page.screenshot({ path: 'example.png' });41 await browser.close();42})();43const { chromium } = require('playwright');44(async () => {45 const browser = await chromium.launch();
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!!