How to use pushInteractions method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberWorkLoop.new.js

Source:ReactFiberWorkLoop.new.js Github

copy

Full Screen

...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) {...

Full Screen

Full Screen

ReactFiberWorkLoop.old.js

Source:ReactFiberWorkLoop.old.js Github

copy

Full Screen

...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 {...

Full Screen

Full Screen

ReactFiberWorkLoop.js

Source:ReactFiberWorkLoop.js Github

copy

Full Screen

...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(...

Full Screen

Full Screen

4 - commitWork.js

Source:4 - commitWork.js Github

copy

Full Screen

...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);...

Full Screen

Full Screen

commitRootImpl.js

Source:commitRootImpl.js Github

copy

Full Screen

...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 () {...

Full Screen

Full Screen

finishSyncRender.js

Source:finishSyncRender.js Github

copy

Full Screen

...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();...

Full Screen

Full Screen

flushPassiveEffectsImpl.js

Source:flushPassiveEffectsImpl.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

StoryReal.js

Source:StoryReal.js Github

copy

Full Screen

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}...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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 } =

Full Screen

Using AI Code Generation

copy

Full Screen

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 } =

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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 () => {

Full Screen

Using AI Code Generation

copy

Full Screen

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 {

Full Screen

Using AI Code Generation

copy

Full Screen

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 {

Full Screen

Using AI Code Generation

copy

Full Screen

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');

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful