Best JavaScript code snippet using playwright-internal
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js
...1905 //循ç¯æ§è¡ scheduleInteractions1906 for (let i = 0; i < expirationTimes.length; i++) {1907 //ä¸scheduleç交äº1908 //请çï¼[Reactæºç 解æä¹scheduleWorkï¼ä¸ï¼](https://juejin.im/post/5d7fa983f265da03cf7ac048)ä¸çãå
ãschedulePendingInteractions()ã1909 scheduleInteractions(1910 root,1911 expirationTimes[i],1912 root.memoizedInteractions,1913 );1914 }1915 }1916 }1917 // åæ¥è°ç¨callback1918 // æµç¨æ¯å¨rootä¸ååcallbackåexpirationTimeï¼1919 // å½æ°çcallbackè°ç¨æ¶ï¼æ¯è¾æ´æ°expirationTime1920 //请çï¼[Reactæºç 解æä¹scheduleWorkï¼ä¸ï¼](https://juejin.im/post/5d885b75f265da03e83baaa7)ä¸çãå
«ãscheduleCallbackForRoot()ã1921 scheduleCallbackForRoot(root, priorityLevel, remainingExpirationTime);1922 }1923 //å¦æ没æå©ä½ç work çè¯ï¼è¯´æ commit æåï¼é£ä¹å°±æ¸
é¤ãé误边çãç list1924 else {1925 // If there's no remaining work, we can clear the set of already failed1926 // error boundaries.1927 legacyErrorBoundariesThatAlreadyFailed = null;1928 }1929 if (enableSchedulerTracing) {1930 //å½æ¬æ¬¡ commit 产ççèä½ç¨è¢«æ¸
é¤åï¼Reactå°±å¯ä»¥æ¸
é¤å·²ç»å®æç交äº1931 if (!rootDidHavePassiveEffects) {1932 // If there are no passive effects, then we can complete the pending interactions.1933 // Otherwise, we'll wait until after the passive effects are flushed.1934 // Wait to do this until after remaining work has been scheduled,1935 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1936 //æ¸
é¤å·²ç»å®æç交äºï¼å¦æ被 suspended æèµ·çè¯ï¼æ交äºçå°åç»åç°1937 finishPendingInteractions(root, expirationTime);1938 }1939 }1940 //devTools ç¸å
³çï¼å¯ä¸ç1941 onCommitRoot(finishedWork.stateNode, expirationTime);1942 //å©ä½ç work æ¯åæ¥ä»»å¡çè¯1943 if (remainingExpirationTime === Sync) {1944 // Count the number of times the root synchronously re-renders without1945 // finishing. If there are too many, it indicates an infinite update loop.1946 //计ç®åæ¥ re-render éæ°æ¸²æç次æ°ï¼å¤ææ¯å¦æ¯æ é循ç¯1947 if (root === rootWithNestedUpdates) {1948 nestedUpdateCount++;1949 } else {1950 nestedUpdateCount = 0;1951 rootWithNestedUpdates = root;1952 }1953 } else {1954 nestedUpdateCount = 0;1955 }1956 //å¦ææè·å°é误çè¯ï¼å°± throw error1957 if (hasUncaughtError) {1958 hasUncaughtError = false;1959 const error = firstUncaughtError;1960 firstUncaughtError = null;1961 throw error;1962 }1963 //å¯ä¸ç1964 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1965 // This is a legacy edge case. We just committed the initial mount of1966 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1967 // synchronously, but layout updates should be deferred until the end1968 // of the batch.1969 return null;1970 }1971 // If layout work was scheduled, flush it now.1972 //ãlayoutãé¶æ®µçä»»å¡å·²ç»è¢«è°åº¦çè¯,ç«å³æ¸
é¤å®1973 //å·æ°åæ¥ä»»å¡éå1974 //请çï¼[Reactæºç 解æä¹scheduleWorkï¼ä¸ï¼](https://juejin.im/post/5d885b75f265da03e83baaa7)ä¸çãåäºãflushSyncCallbackQueue()ã1975 flushSyncCallbackQueue();1976 return null;1977}1978//===========================================================1979//å¾ªç¯ effect é¾ï¼å¯¹æ Snapshot ç effect æ§è¡ commitBeforeMutationEffectOnFiber1980function commitBeforeMutationEffects() {1981 //å¾ªç¯ effect é¾1982 while (nextEffect !== null) {1983 //å¦æ effectTag éæ Snapshot è¿ä¸ª effectTag çè¯1984 //å
³äº&ï¼è¯·ç[å端å°ç¥è¯10ç¹(2020.2.10)](https://mp.weixin.qq.com/s/tt2XcW4GF7oBBZOPwTiCcg)ä¸çã8ãJS ä¸ç & æ¯ä»ä¹ææã1985 if ((nextEffect.effectTag & Snapshot) !== NoEffect) {1986 //dev å¯ä¸ç1987 // setCurrentDebugFiberInDEV(nextEffect);1988 //计 effect çæ°1989 recordEffect();1990 //è·åå½å fiber èç¹1991 const current = nextEffect.alternate;1992 commitBeforeMutationEffectOnFiber(current, nextEffect);1993 //dev å¯ä¸ç1994 // resetCurrentDebugFiberInDEV();1995 }1996 nextEffect = nextEffect.nextEffect;1997 }1998}1999//æ交HostComponentç side effectï¼ä¹å°±æ¯ DOM èç¹çæä½(å¢å æ¹)2000function commitMutationEffects() {2001 // TODO: Should probably move the bulk of this function to commitWork.2002 //å¾ªç¯ effect é¾2003 while (nextEffect !== null) {2004 setCurrentDebugFiberInDEV(nextEffect);2005 const effectTag = nextEffect.effectTag;2006 //å¦æææåèç¹ï¼åå°value 置为''2007 if (effectTag & ContentReset) {2008 commitResetTextContent(nextEffect);2009 }2010 ////å° ref çæå置为 null2011 if (effectTag & Ref) {2012 const current = nextEffect.alternate;2013 if (current !== null) {2014 commitDetachRef(current);2015 }2016 }2017 // The following switch statement is only concerned about placement,2018 // updates, and deletions. To avoid needing to add a case for every possible2019 // bitmap value, we remove the secondary effects from the effect tag and2020 // switch on that value.2021 //以ä¸æ
åµæ¯é对 æ¿æ¢(Placement)ãæ´æ°(Update)å å é¤(Deletion) ç effectTag ç2022 let primaryEffectTag = effectTag & (Placement | Update | Deletion);2023 switch (primaryEffectTag) {2024 //æå
¥æ°èç¹2025 case Placement: {2026 //é对该èç¹ååèç¹è¿è¡æå
¥æä½2027 commitPlacement(nextEffect);2028 // Clear the "placement" from effect tag so that we know that this is2029 // inserted, before any life-cycles like componentDidMount gets called.2030 // TODO: findDOMNode doesn't rely on this any more but isMounted does2031 // and isMounted is deprecated anyway so we should be able to kill this.2032 nextEffect.effectTag &= ~Placement;2033 break;2034 }2035 //æ¿æ¢å¹¶æ´æ°è¯¥èç¹æ¯PlacementåUpdateçç»åï¼å°±ä¸è®²äº2036 case PlacementAndUpdate: {2037 // Placement2038 //é对该èç¹ååèç¹è¿è¡æå
¥æä½2039 commitPlacement(nextEffect);2040 // Clear the "placement" from effect tag so that we know that this is2041 // inserted, before any life-cycles like componentDidMount gets called.2042 nextEffect.effectTag &= ~Placement;2043 // Update2044 const current = nextEffect.alternate;2045 //对 DOM èç¹ä¸çå±æ§è¿è¡æ´æ°2046 commitWork(current, nextEffect);2047 break;2048 }2049 //æ´æ°èç¹2050 //æ§èç¹->æ°èç¹2051 case Update: {2052 const current = nextEffect.alternate;2053 //对 DOM èç¹ä¸çå±æ§è¿è¡æ´æ°2054 commitWork(current, nextEffect);2055 break;2056 }2057 case Deletion: {2058 //å é¤èç¹2059 commitDeletion(nextEffect);2060 break;2061 }2062 }2063 // TODO: Only record a mutation effect if primaryEffectTag is non-zero.2064 //ä¸ç2065 recordEffect();2066 //devï¼ä¸ç2067 resetCurrentDebugFiberInDEV();2068 nextEffect = nextEffect.nextEffect;2069 }2070}2071//â å¾ªç¯ effect é¾ï¼é对ä¸åç fiber ç±»åï¼è¿è¡effect.destroy()/componentDidMount()/callback/node.focus()çæä½2072//â¡ æå® ref çå¼ç¨2073function commitLayoutEffects(2074 root: FiberRoot,2075 committedExpirationTime: ExpirationTime,2076) {2077 // TODO: Should probably move the bulk of this function to commitWork.2078 //å¾ªç¯ effect é¾2079 while (nextEffect !== null) {2080 //dev ç¯å¢ä»£ç ï¼ä¸ç2081 setCurrentDebugFiberInDEV(nextEffect);2082 const effectTag = nextEffect.effectTag;2083 //å¦ææ UpdateãCallback ç effectTag çè¯2084 if (effectTag & (Update | Callback)) {2085 recordEffect();2086 const current = nextEffect.alternate;2087 //éç¹ç FunctionComponent/ClassComponent/HostComponent2088 //â FunctionComponentââæ§è¡effect.destroy()2089 //â¡ ClassComponentââcomponentDidMount()/componentDidUpdate()ï¼effect é¾ââæ§è¡ setState ç callbackï¼capturedEffect é¾æ§è¡ componentDidCatch2090 //⢠HostComponentââå¤ææ¯å¦æ¯èªå¨èç¦ç DOM æ ç¾ï¼æ¯çè¯åè°ç¨ node.focus() è·åç¦ç¹2091 commitLayoutEffectOnFiber(2092 root,2093 current,2094 nextEffect,2095 committedExpirationTime,2096 );2097 }2098 //æå® ref çå¼ç¨2099 if (effectTag & Ref) {2100 recordEffect();2101 //è·å instance å®ä¾ï¼å¹¶æå®ç» ref2102 commitAttachRef(nextEffect);2103 }2104 //å¯ä½ç¨2105 if (effectTag & Passive) {2106 rootDoesHavePassiveEffects = true;2107 }2108 //dev ç¯å¢ï¼ä¸ç2109 resetCurrentDebugFiberInDEV();2110 nextEffect = nextEffect.nextEffect;2111 }2112}2113//æ¸
é¤èä½ç¨2114export function flushPassiveEffects() {2115 if (rootWithPendingPassiveEffects === null) {2116 return false;2117 }2118 const root = rootWithPendingPassiveEffects;2119 const expirationTime = pendingPassiveEffectsExpirationTime;2120 rootWithPendingPassiveEffects = null;2121 pendingPassiveEffectsExpirationTime = NoWork;2122 let prevInteractions: Set<Interaction> | null = null;2123 if (enableSchedulerTracing) {2124 prevInteractions = __interactionsRef.current;2125 __interactionsRef.current = root.memoizedInteractions;2126 }2127 invariant(2128 (executionContext & (RenderContext | CommitContext)) === NoContext,2129 'Cannot flush passive effects while already rendering.',2130 );2131 const prevExecutionContext = executionContext;2132 executionContext |= CommitContext;2133 // Note: This currently assumes there are no passive effects on the root2134 // fiber, because the root is not part of its own effect list. This could2135 // change in the future.2136 //effect é¾è¡¨ä¸ç¬¬ä¸ä¸ªæå¯ä½ç¨ç fiber2137 //æ¯å¦å¨ app() ä¸è°ç¨äº useEffect()2138 let effect = root.current.firstEffect;2139 while (effect !== null) {2140 if (__DEV__) {2141 //å é¤äº dev 代ç 2142 } else {2143 try {2144 //æ§è¡ fiber ä¸çå¯ä½ç¨2145 commitPassiveHookEffects(effect);2146 } catch (error) {2147 invariant(effect !== null, 'Should be working on an effect.');2148 captureCommitPhaseError(effect, error);2149 }2150 }2151 effect = effect.nextEffect;2152 }2153 if (enableSchedulerTracing) {2154 __interactionsRef.current = ((prevInteractions: any): Set<Interaction>);2155 finishPendingInteractions(root, expirationTime);2156 }2157 executionContext = prevExecutionContext;2158 flushSyncCallbackQueue();2159 // If additional passive effects were scheduled, increment a counter. If this2160 // exceeds the limit, we'll fire a warning.2161 nestedPassiveUpdateCount =2162 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2163 return true;2164}2165export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2166 return (2167 legacyErrorBoundariesThatAlreadyFailed !== null &&2168 legacyErrorBoundariesThatAlreadyFailed.has(instance)2169 );2170}2171export function markLegacyErrorBoundaryAsFailed(instance: mixed) {2172 if (legacyErrorBoundariesThatAlreadyFailed === null) {2173 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);2174 } else {2175 legacyErrorBoundariesThatAlreadyFailed.add(instance);2176 }2177}2178function prepareToThrowUncaughtError(error: mixed) {2179 if (!hasUncaughtError) {2180 hasUncaughtError = true;2181 firstUncaughtError = error;2182 }2183}2184export const onUncaughtError = prepareToThrowUncaughtError;2185function captureCommitPhaseErrorOnRoot(2186 rootFiber: Fiber,2187 sourceFiber: Fiber,2188 error: mixed,2189) {2190 const errorInfo = createCapturedValue(error, sourceFiber);2191 const update = createRootErrorUpdate(rootFiber, errorInfo, Sync);2192 enqueueUpdate(rootFiber, update);2193 const root = markUpdateTimeFromFiberToRoot(rootFiber, Sync);2194 if (root !== null) {2195 scheduleCallbackForRoot(root, ImmediatePriority, Sync);2196 }2197}2198export function captureCommitPhaseError(sourceFiber: Fiber, error: mixed) {2199 if (sourceFiber.tag === HostRoot) {2200 // Error was thrown at the root. There is no parent, so the root2201 // itself should capture it.2202 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);2203 return;2204 }2205 let fiber = sourceFiber.return;2206 while (fiber !== null) {2207 if (fiber.tag === HostRoot) {2208 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);2209 return;2210 } else if (fiber.tag === ClassComponent) {2211 const ctor = fiber.type;2212 const instance = fiber.stateNode;2213 if (2214 typeof ctor.getDerivedStateFromError === 'function' ||2215 (typeof instance.componentDidCatch === 'function' &&2216 !isAlreadyFailedLegacyErrorBoundary(instance))2217 ) {2218 const errorInfo = createCapturedValue(error, sourceFiber);2219 const update = createClassErrorUpdate(2220 fiber,2221 errorInfo,2222 // TODO: This is always sync2223 Sync,2224 );2225 enqueueUpdate(fiber, update);2226 const root = markUpdateTimeFromFiberToRoot(fiber, Sync);2227 if (root !== null) {2228 scheduleCallbackForRoot(root, ImmediatePriority, Sync);2229 }2230 return;2231 }2232 }2233 fiber = fiber.return;2234 }2235}2236export function pingSuspendedRoot(2237 root: FiberRoot,2238 thenable: Thenable,2239 suspendedTime: ExpirationTime,2240) {2241 const pingCache = root.pingCache;2242 if (pingCache !== null) {2243 // The thenable resolved, so we no longer need to memoize, because it will2244 // never be thrown again.2245 pingCache.delete(thenable);2246 }2247 if (workInProgressRoot === root && renderExpirationTime === suspendedTime) {2248 // Received a ping at the same priority level at which we're currently2249 // rendering. We might want to restart this render. This should mirror2250 // the logic of whether or not a root suspends once it completes.2251 // TODO: If we're rendering sync either due to Sync, Batched or expired,2252 // we should probably never restart.2253 // If we're suspended with delay, we'll always suspend so we can always2254 // restart. If we're suspended without any updates, it might be a retry.2255 // If it's early in the retry we can restart. We can't know for sure2256 // whether we'll eventually process an update during this render pass,2257 // but it's somewhat unlikely that we get to a ping before that, since2258 // getting to the root most update is usually very fast.2259 if (2260 workInProgressRootExitStatus === RootSuspendedWithDelay ||2261 (workInProgressRootExitStatus === RootSuspended &&2262 workInProgressRootLatestProcessedExpirationTime === Sync &&2263 now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)2264 ) {2265 // Restart from the root. Don't need to schedule a ping because2266 // we're already working on this tree.2267 prepareFreshStack(root, renderExpirationTime);2268 } else {2269 // Even though we can't restart right now, we might get an2270 // opportunity later. So we mark this render as having a ping.2271 workInProgressRootHasPendingPing = true;2272 }2273 return;2274 }2275 const lastPendingTime = root.lastPendingTime;2276 if (lastPendingTime < suspendedTime) {2277 // The root is no longer suspended at this time.2278 return;2279 }2280 const pingTime = root.pingTime;2281 if (pingTime !== NoWork && pingTime < suspendedTime) {2282 // There's already a lower priority ping scheduled.2283 return;2284 }2285 // Mark the time at which this ping was scheduled.2286 root.pingTime = suspendedTime;2287 if (root.finishedExpirationTime === suspendedTime) {2288 // If there's a pending fallback waiting to commit, throw it away.2289 root.finishedExpirationTime = NoWork;2290 root.finishedWork = null;2291 }2292 const currentTime = requestCurrentTime();2293 const priorityLevel = inferPriorityFromExpirationTime(2294 currentTime,2295 suspendedTime,2296 );2297 scheduleCallbackForRoot(root, priorityLevel, suspendedTime);2298}2299export function retryTimedOutBoundary(boundaryFiber: Fiber) {2300 // The boundary fiber (a Suspense component or SuspenseList component)2301 // previously was rendered in its fallback state. One of the promises that2302 // suspended it has resolved, which means at least part of the tree was2303 // likely unblocked. Try rendering again, at a new expiration time.2304 const currentTime = requestCurrentTime();2305 const suspenseConfig = null; // Retries don't carry over the already committed update.2306 const retryTime = computeExpirationForFiber(2307 currentTime,2308 boundaryFiber,2309 suspenseConfig,2310 );2311 // TODO: Special case idle priority?2312 const priorityLevel = inferPriorityFromExpirationTime(currentTime, retryTime);2313 const root = markUpdateTimeFromFiberToRoot(boundaryFiber, retryTime);2314 if (root !== null) {2315 scheduleCallbackForRoot(root, priorityLevel, retryTime);2316 }2317}2318export function resolveRetryThenable(boundaryFiber: Fiber, thenable: Thenable) {2319 let retryCache: WeakSet<Thenable> | Set<Thenable> | null;2320 if (enableSuspenseServerRenderer) {2321 switch (boundaryFiber.tag) {2322 case SuspenseComponent:2323 retryCache = boundaryFiber.stateNode;2324 break;2325 case DehydratedSuspenseComponent:2326 retryCache = boundaryFiber.memoizedState;2327 break;2328 default:2329 invariant(2330 false,2331 'Pinged unknown suspense boundary type. ' +2332 'This is probably a bug in React.',2333 );2334 }2335 } else {2336 retryCache = boundaryFiber.stateNode;2337 }2338 if (retryCache !== null) {2339 // The thenable resolved, so we no longer need to memoize, because it will2340 // never be thrown again.2341 retryCache.delete(thenable);2342 }2343 retryTimedOutBoundary(boundaryFiber);2344}2345// Computes the next Just Noticeable Difference (JND) boundary.2346// The theory is that a person can't tell the difference between small differences in time.2347// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable2348// difference in the experience. However, waiting for longer might mean that we can avoid2349// showing an intermediate loading state. The longer we have already waited, the harder it2350// is to tell small differences in time. Therefore, the longer we've already waited,2351// the longer we can wait additionally. At some point we have to give up though.2352// We pick a train model where the next boundary commits at a consistent schedule.2353// These particular numbers are vague estimates. We expect to adjust them based on research.2354function jnd(timeElapsed: number) {2355 return timeElapsed < 1202356 ? 1202357 : timeElapsed < 4802358 ? 4802359 : timeElapsed < 10802360 ? 10802361 : timeElapsed < 19202362 ? 19202363 : timeElapsed < 30002364 ? 30002365 : timeElapsed < 43202366 ? 43202367 : ceil(timeElapsed / 1960) * 1960;2368}2369function computeMsUntilSuspenseLoadingDelay(2370 mostRecentEventTime: ExpirationTime,2371 committedExpirationTime: ExpirationTime,2372 suspenseConfig: SuspenseConfig,2373) {2374 const busyMinDurationMs = (suspenseConfig.busyMinDurationMs: any) | 0;2375 if (busyMinDurationMs <= 0) {2376 return 0;2377 }2378 const busyDelayMs = (suspenseConfig.busyDelayMs: any) | 0;2379 // Compute the time until this render pass would expire.2380 const currentTimeMs: number = now();2381 const eventTimeMs: number = inferTimeFromExpirationTimeWithSuspenseConfig(2382 mostRecentEventTime,2383 suspenseConfig,2384 );2385 const timeElapsed = currentTimeMs - eventTimeMs;2386 if (timeElapsed <= busyDelayMs) {2387 // If we haven't yet waited longer than the initial delay, we don't2388 // have to wait any additional time.2389 return 0;2390 }2391 const msUntilTimeout = busyDelayMs + busyMinDurationMs - timeElapsed;2392 // This is the value that is passed to `setTimeout`.2393 return msUntilTimeout;2394}2395//é²æ¢æ é循ç¯å°åµå¥æ´æ°2396function checkForNestedUpdates() {2397 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {2398 nestedUpdateCount = 0;2399 rootWithNestedUpdates = null;2400 invariant(2401 false,2402 'Maximum update depth exceeded. This can happen when a component ' +2403 'repeatedly calls setState inside componentWillUpdate or ' +2404 'componentDidUpdate. React limits the number of nested updates to ' +2405 'prevent infinite loops.',2406 );2407 }2408}2409function flushRenderPhaseStrictModeWarningsInDEV() {2410 if (__DEV__) {2411 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();2412 ReactStrictModeWarnings.flushLegacyContextWarning();2413 if (warnAboutDeprecatedLifecycles) {2414 ReactStrictModeWarnings.flushPendingDeprecationWarnings();2415 }2416 }2417}2418function stopFinishedWorkLoopTimer() {2419 const didCompleteRoot = true;2420 stopWorkLoopTimer(interruptedBy, didCompleteRoot);2421 interruptedBy = null;2422}2423//åæ¢è®¡æ¶2424function stopInterruptedWorkLoopTimer() {2425 // TODO: Track which fiber caused the interruption.2426 /*_didCompleteRoot <=> didCompleteRoot*/2427 const didCompleteRoot = false;2428 stopWorkLoopTimer(interruptedBy, didCompleteRoot);2429 interruptedBy = null;2430}2431//å¤ææ¯å¦æé«ä¼å
级任å¡ææå½åæ£å¨æ§è¡çä»»å¡2432function checkForInterruption(2433 fiberThatReceivedUpdate: Fiber,2434 updateExpirationTime: ExpirationTime,2435) {2436 //å¦æä»»å¡æ£å¨æ§è¡ï¼å¹¶ä¸å¼æ¥ä»»å¡å·²ç»æ§è¡å°ä¸åäºï¼2437 //ä½æ¯ç°å¨éè¦ææ§è¡æ交ç»æµè§å¨ï¼å»æ§è¡ä¼å
级æ´é«çä»»å¡2438 if (2439 enableUserTimingAPI &&2440 workInProgressRoot !== null &&2441 updateExpirationTime > renderExpirationTime2442 ) {2443 //ææå½åä»»å¡ï¼ä¼å
æ§è¡æ°çupdate2444 interruptedBy = fiberThatReceivedUpdate;2445 }2446}2447let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;2448function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {2449 if (__DEV__) {2450 const tag = fiber.tag;2451 if (2452 tag !== HostRoot &&2453 tag !== ClassComponent &&2454 tag !== FunctionComponent &&2455 tag !== ForwardRef &&2456 tag !== MemoComponent &&2457 tag !== SimpleMemoComponent2458 ) {2459 // Only warn for user-defined components, not internal ones like Suspense.2460 return;2461 }2462 // We show the whole stack but dedupe on the top component's name because2463 // the problematic code almost always lies inside that component.2464 const componentName = getComponentName(fiber.type) || 'ReactComponent';2465 if (didWarnStateUpdateForUnmountedComponent !== null) {2466 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {2467 return;2468 }2469 didWarnStateUpdateForUnmountedComponent.add(componentName);2470 } else {2471 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);2472 }2473 warningWithoutStack(2474 false,2475 "Can't perform a React state update on an unmounted component. This " +2476 'is a no-op, but it indicates a memory leak in your application. To ' +2477 'fix, cancel all subscriptions and asynchronous tasks in %s.%s',2478 tag === ClassComponent2479 ? 'the componentWillUnmount method'2480 : 'a useEffect cleanup function',2481 getStackByFiberInDevAndProd(fiber),2482 );2483 }2484}2485let beginWork;2486if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {2487 let dummyFiber = null;2488 beginWork = (current, unitOfWork, expirationTime) => {2489 // If a component throws an error, we replay it again in a synchronously2490 // dispatched event, so that the debugger will treat it as an uncaught2491 // error See ReactErrorUtils for more information.2492 // Before entering the begin phase, copy the work-in-progress onto a dummy2493 // fiber. If beginWork throws, we'll use this to reset the state.2494 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(2495 dummyFiber,2496 unitOfWork,2497 );2498 try {2499 return originalBeginWork(current, unitOfWork, expirationTime);2500 } catch (originalError) {2501 if (2502 originalError !== null &&2503 typeof originalError === 'object' &&2504 typeof originalError.then === 'function'2505 ) {2506 // Don't replay promises. Treat everything else like an error.2507 throw originalError;2508 }2509 // Keep this code in sync with renderRoot; any changes here must have2510 // corresponding changes there.2511 resetContextDependencies();2512 resetHooks();2513 // Unwind the failed stack frame2514 unwindInterruptedWork(unitOfWork);2515 // Restore the original properties of the fiber.2516 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);2517 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {2518 // Reset the profiler timer.2519 startProfilerTimer(unitOfWork);2520 }2521 // Run beginWork again.2522 invokeGuardedCallback(2523 null,2524 originalBeginWork,2525 null,2526 current,2527 unitOfWork,2528 expirationTime,2529 );2530 if (hasCaughtError()) {2531 const replayError = clearCaughtError();2532 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.2533 // Rethrow this error instead of the original one.2534 throw replayError;2535 } else {2536 // This branch is reachable if the render phase is impure.2537 throw originalError;2538 }2539 }2540 };2541} else {2542 beginWork = originalBeginWork;2543}2544let didWarnAboutUpdateInRender = false;2545let didWarnAboutUpdateInGetChildContext = false;2546function warnAboutInvalidUpdatesOnClassComponentsInDEV(fiber) {2547 if (__DEV__) {2548 if (fiber.tag === ClassComponent) {2549 switch (ReactCurrentDebugFiberPhaseInDEV) {2550 case 'getChildContext':2551 if (didWarnAboutUpdateInGetChildContext) {2552 return;2553 }2554 warningWithoutStack(2555 false,2556 'setState(...): Cannot call setState() inside getChildContext()',2557 );2558 didWarnAboutUpdateInGetChildContext = true;2559 break;2560 case 'render':2561 if (didWarnAboutUpdateInRender) {2562 return;2563 }2564 warningWithoutStack(2565 false,2566 'Cannot update during an existing state transition (such as ' +2567 'within `render`). Render methods should be a pure function of ' +2568 'props and state.',2569 );2570 didWarnAboutUpdateInRender = true;2571 break;2572 }2573 }2574 }2575}2576export const IsThisRendererActing = {current: (false: boolean)};2577export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {2578 if (__DEV__) {2579 if (2580 warnsIfNotActing === true &&2581 IsSomeRendererActing.current === true &&2582 IsThisRendererActing.current !== true2583 ) {2584 warningWithoutStack(2585 false,2586 "It looks like you're using the wrong act() around your test interactions.\n" +2587 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' +2588 '// for react-dom:\n' +2589 "import {act} from 'react-dom/test-utils';\n" +2590 '//...\n' +2591 'act(() => ...);\n\n' +2592 '// for react-test-renderer:\n' +2593 "import TestRenderer from 'react-test-renderer';\n" +2594 'const {act} = TestRenderer;\n' +2595 '//...\n' +2596 'act(() => ...);' +2597 '%s',2598 getStackByFiberInDevAndProd(fiber),2599 );2600 }2601 }2602}2603export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {2604 if (__DEV__) {2605 if (2606 warnsIfNotActing === true &&2607 (fiber.mode & StrictMode) !== NoMode &&2608 IsSomeRendererActing.current === false &&2609 IsThisRendererActing.current === false2610 ) {2611 warningWithoutStack(2612 false,2613 'An update to %s ran an effect, but was not wrapped in act(...).\n\n' +2614 'When testing, code that causes React state updates should be ' +2615 'wrapped into act(...):\n\n' +2616 'act(() => {\n' +2617 ' /* fire events that update state */\n' +2618 '});\n' +2619 '/* assert on the output */\n\n' +2620 "This ensures that you're testing the behavior the user would see " +2621 'in the browser.' +2622 ' Learn more at https://fb.me/react-wrap-tests-with-act' +2623 '%s',2624 getComponentName(fiber.type),2625 getStackByFiberInDevAndProd(fiber),2626 );2627 }2628 }2629}2630function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {2631 if (__DEV__) {2632 if (2633 warnsIfNotActing === true &&2634 executionContext === NoContext &&2635 IsSomeRendererActing.current === false &&2636 IsThisRendererActing.current === false2637 ) {2638 warningWithoutStack(2639 false,2640 'An update to %s inside a test was not wrapped in act(...).\n\n' +2641 'When testing, code that causes React state updates should be ' +2642 'wrapped into act(...):\n\n' +2643 'act(() => {\n' +2644 ' /* fire events that update state */\n' +2645 '});\n' +2646 '/* assert on the output */\n\n' +2647 "This ensures that you're testing the behavior the user would see " +2648 'in the browser.' +2649 ' Learn more at https://fb.me/react-wrap-tests-with-act' +2650 '%s',2651 getComponentName(fiber.type),2652 getStackByFiberInDevAndProd(fiber),2653 );2654 }2655 }2656}2657export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;2658let componentsWithSuspendedDiscreteUpdates = null;2659export function checkForWrongSuspensePriorityInDEV(sourceFiber: Fiber) {2660 if (__DEV__) {2661 if (2662 (sourceFiber.mode & ConcurrentMode) !== NoEffect &&2663 // Check if we're currently rendering a discrete update. Ideally, all we2664 // would need to do is check the current priority level. But we currently2665 // have no rigorous way to distinguish work that was scheduled at user-2666 // blocking priority from work that expired a bit and was "upgraded" to2667 // a higher priority. That's because we don't schedule separate callbacks2668 // for every level, only the highest priority level per root. The priority2669 // of subsequent levels is inferred from the expiration time, but this is2670 // an imprecise heuristic.2671 //2672 // However, we do store the last discrete pending update per root. So we2673 // can reliably compare to that one. (If we broaden this warning to include2674 // high pri updates that aren't discrete, then this won't be sufficient.)2675 //2676 // My rationale is that it's better for this warning to have false2677 // negatives than false positives.2678 rootsWithPendingDiscreteUpdates !== null &&2679 workInProgressRoot !== null &&2680 renderExpirationTime ===2681 rootsWithPendingDiscreteUpdates.get(workInProgressRoot)2682 ) {2683 // Add the component name to a set.2684 const componentName = getComponentName(sourceFiber.type);2685 if (componentsWithSuspendedDiscreteUpdates === null) {2686 componentsWithSuspendedDiscreteUpdates = new Set([componentName]);2687 } else {2688 componentsWithSuspendedDiscreteUpdates.add(componentName);2689 }2690 }2691 }2692}2693function flushSuspensePriorityWarningInDEV() {2694 if (__DEV__) {2695 if (componentsWithSuspendedDiscreteUpdates !== null) {2696 const componentNames = [];2697 componentsWithSuspendedDiscreteUpdates.forEach(name => {2698 componentNames.push(name);2699 });2700 componentsWithSuspendedDiscreteUpdates = null;2701 // TODO: A more helpful version of this message could include the names of2702 // the component that were updated, not the ones that suspended. To do2703 // that we'd need to track all the components that updated during this2704 // render, perhaps using the same mechanism as `markRenderEventTime`.2705 warningWithoutStack(2706 false,2707 'The following components suspended during a user-blocking update: %s' +2708 '\n\n' +2709 'Updates triggered by user interactions (e.g. click events) are ' +2710 'considered user-blocking by default. They should not suspend. ' +2711 'Updates that can afford to take a bit longer should be wrapped ' +2712 'with `Scheduler.next` (or an equivalent abstraction). This ' +2713 'typically includes any update that shows new content, like ' +2714 'a navigation.' +2715 '\n\n' +2716 'Generally, you should split user interactions into at least two ' +2717 'seprate updates: a user-blocking update to provide immediate ' +2718 'feedback, and another update to perform the actual change.',2719 // TODO: Add link to React docs with more information, once it exists2720 componentNames.sort().join(', '),2721 );2722 }2723 }2724}2725function computeThreadID(root, expirationTime) {2726 // Interaction threads are unique per root and expiration time.2727 return expirationTime * 1000 + root.interactionThreadID;2728}2729export function markSpawnedWork(expirationTime: ExpirationTime) {2730 if (!enableSchedulerTracing) {2731 return;2732 }2733 if (spawnedWorkDuringRender === null) {2734 spawnedWorkDuringRender = [expirationTime];2735 } else {2736 spawnedWorkDuringRender.push(expirationTime);2737 }2738}2739//ä¸scheduleç交äº2740function scheduleInteractions(root, expirationTime, interactions) {2741 if (!enableSchedulerTracing) {2742 return;2743 }2744 //å½interactionsåå¨æ¶2745 if (interactions.size > 0) {2746 //è·åFiberRootçpendingInteractionMapå±æ§2747 const pendingInteractionMap = root.pendingInteractionMap;2748 //è·åpendingInteractionsçexpirationTime2749 const pendingInteractions = pendingInteractionMap.get(expirationTime);2750 //å¦æpendingInteractionsä¸ä¸ºç©ºçè¯2751 if (pendingInteractions != null) {2752 //éå并æ´æ°è¿æªè°åº¦çåæ¥ä»»å¡çæ°é2753 interactions.forEach(interaction => {2754 if (!pendingInteractions.has(interaction)) {2755 // Update the pending async work count for previously unscheduled interaction.2756 interaction.__count++;2757 }2758 pendingInteractions.add(interaction);2759 });2760 }2761 //å¦ååå§åpendingInteractionMap2762 //并ç»è®¡å½åè°åº¦ä¸åæ¥ä»»å¡çæ°é2763 else {2764 pendingInteractionMap.set(expirationTime, new Set(interactions));2765 // Update the pending async work count for the current interactions.2766 interactions.forEach(interaction => {2767 interaction.__count++;2768 });2769 }2770 //计ç®å¹¶å¾åºçº¿ç¨çid2771 const subscriber = __subscriberRef.current;2772 if (subscriber !== null) {2773 //è¿ä¸ªææ¶ä¸çäº2774 const threadID = computeThreadID(root, expirationTime);2775 //æ£æµè¿äºä»»å¡æ¯å¦ä¼æ¥é2776 subscriber.onWorkScheduled(interactions, threadID);2777 }2778 }2779}2780//è·è¸ªè¿äºupdateï¼å¹¶è®¡æ°ãæ£æµå®ä»¬æ¯å¦ä¼æ¥é2781function schedulePendingInteractions(root, expirationTime) {2782 // This is called when work is scheduled on a root.2783 // It associates the current interactions with the newly-scheduled expiration.2784 // They will be restored when that expiration is later committed.2785 //å½è°åº¦å¼å§æ¶å°±æ§è¡ï¼æ¯è°åº¦ä¸ä¸ªupdateï¼å°±æ´æ°è·è¸ªæ 2786 if (!enableSchedulerTracing) {2787 return;2788 }2789 //è°åº¦ç"交äº"2790 scheduleInteractions(root, expirationTime, __interactionsRef.current);2791}2792//å°è°åº¦ä¼å
级é«çinteractionå å
¥å°interactionsä¸2793function startWorkOnPendingInteractions(root, expirationTime) {2794 // This is called when new work is started on a root.2795 if (!enableSchedulerTracing) {2796 return;2797 }2798 // Determine which interactions this batch of work currently includes, So that2799 // we can accurately attribute time spent working on it, And so that cascading2800 // work triggered during the render phase will be associated with it.2801 // ç¡®å®è¿æ¹å·¥ä½å½åå
æ¬åªäºäº¤äºï¼ä»¥ä¾¿æ们å¯ä»¥åç¡®å°å°è±è´¹å¨å·¥ä½ä¸çæ¶é´å½å äºæ¤ï¼ä»¥ä¾¿å¨æ¸²æé¶æ®µè§¦åç级èå·¥ä½å°ä¸ä¹ç¸å
³èã2802 const interactions: Set<Interaction> = new Set();2803 root.pendingInteractionMap.forEach(2804 (scheduledInteractions, scheduledExpirationTime) => {...
ReactFiberWorkLoop.new.js
Source:ReactFiberWorkLoop.new.js
...1829 if (spawnedWorkDuringRender !== null) {1830 const expirationTimes = spawnedWorkDuringRender;1831 spawnedWorkDuringRender = null;1832 for (let i = 0; i < expirationTimes.length; i++) {1833 scheduleInteractions(1834 root,1835 expirationTimes[i],1836 root.memoizedInteractions,1837 );1838 }1839 }1840 schedulePendingInteractions(root, remainingLanes);1841 }1842 } else {1843 // If there's no remaining work, we can clear the set of already failed1844 // error boundaries.1845 legacyErrorBoundariesThatAlreadyFailed = null;1846 }1847 if (__DEV__ && enableDoubleInvokingEffects) {1848 if (!rootDidHavePassiveEffects) {1849 commitDoubleInvokeEffectsInDEV(root.current, false);1850 }1851 }1852 if (enableSchedulerTracing) {1853 if (!rootDidHavePassiveEffects) {1854 // If there are no passive effects, then we can complete the pending interactions.1855 // Otherwise, we'll wait until after the passive effects are flushed.1856 // Wait to do this until after remaining work has been scheduled,1857 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1858 finishPendingInteractions(root, lanes);1859 }1860 }1861 if (remainingLanes === SyncLane) {1862 // Count the number of times the root synchronously re-renders without1863 // finishing. If there are too many, it indicates an infinite update loop.1864 if (root === rootWithNestedUpdates) {1865 nestedUpdateCount++;1866 } else {1867 nestedUpdateCount = 0;1868 rootWithNestedUpdates = root;1869 }1870 } else {1871 nestedUpdateCount = 0;1872 }1873 onCommitRootDevTools(finishedWork.stateNode, renderPriorityLevel);1874 if (__DEV__) {1875 onCommitRootTestSelector();1876 }1877 // Always call this before exiting `commitRoot`, to ensure that any1878 // additional work on this root is scheduled.1879 ensureRootIsScheduled(root, now());1880 if (hasUncaughtError) {1881 hasUncaughtError = false;1882 const error = firstUncaughtError;1883 firstUncaughtError = null;1884 throw error;1885 }1886 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1887 if (__DEV__) {1888 if (enableDebugTracing) {1889 logCommitStopped();1890 }1891 }1892 if (enableSchedulingProfiler) {1893 markCommitStopped();1894 }1895 // This is a legacy edge case. We just committed the initial mount of1896 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1897 // synchronously, but layout updates should be deferred until the end1898 // of the batch.1899 return null;1900 }1901 // If layout work was scheduled, flush it now.1902 flushSyncCallbackQueue();1903 if (__DEV__) {1904 if (enableDebugTracing) {1905 logCommitStopped();1906 }1907 }1908 if (enableSchedulingProfiler) {1909 markCommitStopped();1910 }1911 return null;1912}1913function commitBeforeMutationEffects(firstChild: Fiber) {1914 let fiber = firstChild;1915 while (fiber !== null) {1916 // å¤çéè¦å é¤çfiber autoFocusãblur é»è¾ã1917 if (fiber.deletions !== null) {1918 commitBeforeMutationEffectsDeletions(fiber.deletions);1919 }1920 // éå½è°ç¨å¤çåèç¹1921 if (fiber.child !== null) {1922 const primarySubtreeFlags = fiber.subtreeFlags & BeforeMutationMask;1923 if (primarySubtreeFlags !== NoFlags) {1924 commitBeforeMutationEffects(fiber.child);1925 }1926 }1927 if (__DEV__) {1928 setCurrentDebugFiberInDEV(fiber);1929 invokeGuardedCallback(null, commitBeforeMutationEffectsImpl, null, fiber);1930 if (hasCaughtError()) {1931 const error = clearCaughtError();1932 captureCommitPhaseError(fiber, fiber.return, error);1933 }1934 resetCurrentDebugFiberInDEV();1935 } else {1936 try {1937 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1938 // å¼æ¥è°åº¦useEffect1939 commitBeforeMutationEffectsImpl(fiber);1940 } catch (error) {1941 captureCommitPhaseError(fiber, fiber.return, error);1942 }1943 }1944 // è¿åå
å¼èç¹ï¼æ¥ç循ç¯1945 fiber = fiber.sibling;1946 }1947}1948function commitBeforeMutationEffectsImpl(fiber: Fiber) {1949 const current = fiber.alternate;1950 const flags = fiber.flags;1951 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1952 // Check to see if the focused element was inside of a hidden (Suspense) subtree.1953 // TODO: Move this out of the hot path using a dedicated effect tag.1954 if (1955 fiber.tag === SuspenseComponent &&1956 isSuspenseBoundaryBeingHidden(current, fiber) &&1957 doesFiberContain(fiber, focusedInstanceHandle)1958 ) {1959 shouldFireAfterActiveInstanceBlur = true;1960 beforeActiveInstanceBlur();1961 }1962 }1963 if ((flags & Snapshot) !== NoFlags) {1964 setCurrentDebugFiberInDEV(fiber);1965 // è°ç¨ getSnapshotBeforeUpdate çå½å¨æ1966 commitBeforeMutationEffectOnFiber(current, fiber);1967 resetCurrentDebugFiberInDEV();1968 }1969 // è°åº¦useEffect1970 if ((flags & Passive) !== NoFlags) {1971 // If there are passive effects, schedule a callback to flush at1972 // the earliest opportunity.1973 if (!rootDoesHavePassiveEffects) {1974 rootDoesHavePassiveEffects = true;1975 scheduleCallback(NormalSchedulerPriority, () => {1976 flushPassiveEffects();1977 return null;1978 });1979 }1980 }1981}1982function commitBeforeMutationEffectsDeletions(deletions: Array<Fiber>) {1983 for (let i = 0; i < deletions.length; i++) {1984 const fiber = deletions[i];1985 // TODO (effects) It would be nice to avoid calling doesFiberContain()1986 // Maybe we can repurpose one of the subtreeFlags positions for this instead?1987 // Use it to store which part of the tree the focused instance is in?1988 // This assumes we can safely determine that instance during the "render" phase.1989 if (doesFiberContain(fiber, ((focusedInstanceHandle: any): Fiber))) {1990 shouldFireAfterActiveInstanceBlur = true;1991 beforeActiveInstanceBlur();1992 }1993 }1994}1995function commitMutationEffects(1996 firstChild: Fiber,1997 root: FiberRoot,1998 renderPriorityLevel: ReactPriorityLevel,1999) {2000 let fiber = firstChild;2001 while (fiber !== null) {2002 const deletions = fiber.deletions;2003 if (deletions !== null) {2004 commitMutationEffectsDeletions(2005 deletions,2006 fiber,2007 root,2008 renderPriorityLevel,2009 );2010 }2011 if (fiber.child !== null) {2012 const mutationFlags = fiber.subtreeFlags & MutationMask;2013 if (mutationFlags !== NoFlags) {2014 commitMutationEffects(fiber.child, root, renderPriorityLevel);2015 }2016 }2017 if (__DEV__) {2018 setCurrentDebugFiberInDEV(fiber);2019 invokeGuardedCallback(2020 null,2021 commitMutationEffectsImpl,2022 null,2023 fiber,2024 root,2025 renderPriorityLevel,2026 );2027 if (hasCaughtError()) {2028 const error = clearCaughtError();2029 captureCommitPhaseError(fiber, fiber.return, error);2030 }2031 resetCurrentDebugFiberInDEV();2032 } else {2033 try {2034 commitMutationEffectsImpl(fiber, root, renderPriorityLevel);2035 } catch (error) {2036 captureCommitPhaseError(fiber, fiber.return, error);2037 }2038 }2039 fiber = fiber.sibling;2040 }2041}2042function commitMutationEffectsImpl(2043 fiber: Fiber,2044 root: FiberRoot,2045 renderPriorityLevel,2046) {2047 const flags = fiber.flags;2048 if (flags & ContentReset) {2049 commitResetTextContent(fiber);2050 }2051 if (flags & Ref) {2052 const current = fiber.alternate;2053 if (current !== null) {2054 commitDetachRef(current);2055 }2056 if (enableScopeAPI) {2057 // TODO: This is a temporary solution that allowed us to transition away from React Flare on www.2058 if (fiber.tag === ScopeComponent) {2059 commitAttachRef(fiber);2060 }2061 }2062 }2063 // The following switch statement is only concerned about placement,2064 // updates, and deletions. To avoid needing to add a case for every possible2065 // bitmap value, we remove the secondary effects from the effect tag and2066 // switch on that value.2067 const primaryFlags = flags & (Placement | Update | Hydrating);2068 switch (primaryFlags) {2069 case Placement: {2070 commitPlacement(fiber);2071 // Clear the "placement" from effect tag so that we know that this is2072 // inserted, before any life-cycles like componentDidMount gets called.2073 // TODO: findDOMNode doesn't rely on this any more but isMounted does2074 // and isMounted is deprecated anyway so we should be able to kill this.2075 fiber.flags &= ~Placement;2076 break;2077 }2078 case PlacementAndUpdate: {2079 // Placement2080 commitPlacement(fiber);2081 // Clear the "placement" from effect tag so that we know that this is2082 // inserted, before any life-cycles like componentDidMount gets called.2083 fiber.flags &= ~Placement;2084 // Update2085 const current = fiber.alternate;2086 commitWork(current, fiber);2087 break;2088 }2089 case Hydrating: {2090 fiber.flags &= ~Hydrating;2091 break;2092 }2093 case HydratingAndUpdate: {2094 fiber.flags &= ~Hydrating;2095 // Update2096 const current = fiber.alternate;2097 commitWork(current, fiber);2098 break;2099 }2100 case Update: {2101 const current = fiber.alternate;2102 commitWork(current, fiber);2103 break;2104 }2105 }2106}2107function commitMutationEffectsDeletions(2108 deletions: Array<Fiber>,2109 nearestMountedAncestor: Fiber,2110 root: FiberRoot,2111 renderPriorityLevel,2112) {2113 for (let i = 0; i < deletions.length; i++) {2114 const childToDelete = deletions[i];2115 if (__DEV__) {2116 invokeGuardedCallback(2117 null,2118 commitDeletion,2119 null,2120 root,2121 childToDelete,2122 nearestMountedAncestor,2123 renderPriorityLevel,2124 );2125 if (hasCaughtError()) {2126 const error = clearCaughtError();2127 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2128 }2129 } else {2130 try {2131 commitDeletion(2132 root,2133 childToDelete,2134 nearestMountedAncestor,2135 renderPriorityLevel,2136 );2137 } catch (error) {2138 captureCommitPhaseError(childToDelete, nearestMountedAncestor, error);2139 }2140 }2141 }2142}2143export function schedulePassiveEffectCallback() {2144 if (!rootDoesHavePassiveEffects) {2145 rootDoesHavePassiveEffects = true;2146 scheduleCallback(NormalSchedulerPriority, () => {2147 flushPassiveEffects();2148 return null;2149 });2150 }2151}2152export function flushPassiveEffects(): boolean {2153 // Returns whether passive effects were flushed.2154 if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {2155 const priorityLevel =2156 pendingPassiveEffectsRenderPriority > NormalSchedulerPriority2157 ? NormalSchedulerPriority2158 : pendingPassiveEffectsRenderPriority;2159 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;2160 if (decoupleUpdatePriorityFromScheduler) {2161 const previousLanePriority = getCurrentUpdateLanePriority();2162 try {2163 setCurrentUpdateLanePriority(2164 schedulerPriorityToLanePriority(priorityLevel),2165 );2166 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2167 } finally {2168 setCurrentUpdateLanePriority(previousLanePriority);2169 }2170 } else {2171 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);2172 }2173 }2174 return false;2175}2176function flushPassiveMountEffects(root, firstChild: Fiber): void {2177 let fiber = firstChild;2178 while (fiber !== null) {2179 let prevProfilerOnStack = null;2180 if (enableProfilerTimer && enableProfilerCommitHooks) {2181 if (fiber.tag === Profiler) {2182 prevProfilerOnStack = nearestProfilerOnStack;2183 nearestProfilerOnStack = fiber;2184 }2185 }2186 const primarySubtreeFlags = fiber.subtreeFlags & PassiveMask;2187 if (fiber.child !== null && primarySubtreeFlags !== NoFlags) {2188 flushPassiveMountEffects(root, fiber.child);2189 }2190 if ((fiber.flags & Passive) !== NoFlags) {2191 if (__DEV__) {2192 setCurrentDebugFiberInDEV(fiber);2193 invokeGuardedCallback(2194 null,2195 commitPassiveMountOnFiber,2196 null,2197 root,2198 fiber,2199 );2200 if (hasCaughtError()) {2201 const error = clearCaughtError();2202 captureCommitPhaseError(fiber, fiber.return, error);2203 }2204 resetCurrentDebugFiberInDEV();2205 } else {2206 try {2207 commitPassiveMountOnFiber(root, fiber);2208 } catch (error) {2209 captureCommitPhaseError(fiber, fiber.return, error);2210 }2211 }2212 }2213 if (enableProfilerTimer && enableProfilerCommitHooks) {2214 if (fiber.tag === Profiler) {2215 // Bubble times to the next nearest ancestor Profiler.2216 // After we process that Profiler, we'll bubble further up.2217 if (prevProfilerOnStack !== null) {2218 prevProfilerOnStack.stateNode.passiveEffectDuration +=2219 fiber.stateNode.passiveEffectDuration;2220 }2221 nearestProfilerOnStack = prevProfilerOnStack;2222 }2223 }2224 fiber = fiber.sibling;2225 }2226}2227function flushPassiveUnmountEffects(firstChild: Fiber): void {2228 let fiber = firstChild;2229 while (fiber !== null) {2230 const deletions = fiber.deletions;2231 if (deletions !== null) {2232 for (let i = 0; i < deletions.length; i++) {2233 const fiberToDelete = deletions[i];2234 flushPassiveUnmountEffectsInsideOfDeletedTree(fiberToDelete, fiber);2235 // Now that passive effects have been processed, it's safe to detach lingering pointers.2236 detachFiberAfterEffects(fiberToDelete);2237 }2238 }2239 const child = fiber.child;2240 if (child !== null) {2241 // If any children have passive effects then traverse the subtree.2242 // Note that this requires checking subtreeFlags of the current Fiber,2243 // rather than the subtreeFlags/effectsTag of the first child,2244 // since that would not cover passive effects in siblings.2245 const passiveFlags = fiber.subtreeFlags & PassiveMask;2246 if (passiveFlags !== NoFlags) {2247 flushPassiveUnmountEffects(child);2248 }2249 }2250 const primaryFlags = fiber.flags & Passive;2251 if (primaryFlags !== NoFlags) {2252 setCurrentDebugFiberInDEV(fiber);2253 commitPassiveUnmountOnFiber(fiber);2254 resetCurrentDebugFiberInDEV();2255 }2256 fiber = fiber.sibling;2257 }2258}2259function flushPassiveUnmountEffectsInsideOfDeletedTree(2260 fiberToDelete: Fiber,2261 nearestMountedAncestor: Fiber,2262): void {2263 if ((fiberToDelete.subtreeFlags & PassiveStatic) !== NoFlags) {2264 // If any children have passive effects then traverse the subtree.2265 // Note that this requires checking subtreeFlags of the current Fiber,2266 // rather than the subtreeFlags/effectsTag of the first child,2267 // since that would not cover passive effects in siblings.2268 let child = fiberToDelete.child;2269 while (child !== null) {2270 flushPassiveUnmountEffectsInsideOfDeletedTree(2271 child,2272 nearestMountedAncestor,2273 );2274 child = child.sibling;2275 }2276 }2277 if ((fiberToDelete.flags & PassiveStatic) !== NoFlags) {2278 setCurrentDebugFiberInDEV(fiberToDelete);2279 commitPassiveUnmountInsideDeletedTreeOnFiber(2280 fiberToDelete,2281 nearestMountedAncestor,2282 );2283 resetCurrentDebugFiberInDEV();2284 }2285}2286function flushPassiveEffectsImpl() {2287 if (rootWithPendingPassiveEffects === null) {2288 return false;2289 }2290 const root = rootWithPendingPassiveEffects;2291 const lanes = pendingPassiveEffectsLanes;2292 rootWithPendingPassiveEffects = null;2293 pendingPassiveEffectsLanes = NoLanes;2294 invariant(2295 (executionContext & (RenderContext | CommitContext)) === NoContext,2296 'Cannot flush passive effects while already rendering.',2297 );2298 if (__DEV__) {2299 if (enableDebugTracing) {2300 logPassiveEffectsStarted(lanes);2301 }2302 }2303 if (enableSchedulingProfiler) {2304 markPassiveEffectsStarted(lanes);2305 }2306 if (__DEV__) {2307 isFlushingPassiveEffects = true;2308 }2309 const prevExecutionContext = executionContext;2310 executionContext |= CommitContext;2311 const prevInteractions = pushInteractions(root);2312 // It's important that ALL pending passive effect destroy functions are called2313 // before ANY passive effect create functions are called.2314 // Otherwise effects in sibling components might interfere with each other.2315 // e.g. a destroy function in one component may unintentionally override a ref2316 // value set by a create function in another component.2317 // Layout effects have the same constraint.2318 flushPassiveUnmountEffects(root.current);2319 flushPassiveMountEffects(root, root.current);2320 if (__DEV__) {2321 if (enableDebugTracing) {2322 logPassiveEffectsStopped();2323 }2324 }2325 if (enableSchedulingProfiler) {2326 markPassiveEffectsStopped();2327 }2328 if (__DEV__ && enableDoubleInvokingEffects) {2329 commitDoubleInvokeEffectsInDEV(root.current, true);2330 }2331 if (__DEV__) {2332 isFlushingPassiveEffects = false;2333 }2334 if (enableSchedulerTracing) {2335 popInteractions(((prevInteractions: any): Set<Interaction>));2336 finishPendingInteractions(root, lanes);2337 }2338 executionContext = prevExecutionContext;2339 flushSyncCallbackQueue();2340 // If additional passive effects were scheduled, increment a counter. If this2341 // exceeds the limit, we'll fire a warning.2342 nestedPassiveUpdateCount =2343 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;2344 return true;2345}2346export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {2347 return (2348 legacyErrorBoundariesThatAlreadyFailed !== null &&2349 legacyErrorBoundariesThatAlreadyFailed.has(instance)2350 );2351}2352export function markLegacyErrorBoundaryAsFailed(instance: mixed) {2353 if (legacyErrorBoundariesThatAlreadyFailed === null) {2354 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);2355 } else {2356 legacyErrorBoundariesThatAlreadyFailed.add(instance);2357 }2358}2359function prepareToThrowUncaughtError(error: mixed) {2360 if (!hasUncaughtError) {2361 hasUncaughtError = true;2362 firstUncaughtError = error;2363 }2364}2365export const onUncaughtError = prepareToThrowUncaughtError;2366function captureCommitPhaseErrorOnRoot(2367 rootFiber: Fiber,2368 sourceFiber: Fiber,2369 error: mixed,2370) {2371 const errorInfo = createCapturedValue(error, sourceFiber);2372 const update = createRootErrorUpdate(rootFiber, errorInfo, (SyncLane: Lane));2373 enqueueUpdate(rootFiber, update);2374 const eventTime = requestEventTime();2375 const root = markUpdateLaneFromFiberToRoot(rootFiber, (SyncLane: Lane));2376 if (root !== null) {2377 markRootUpdated(root, SyncLane, eventTime);2378 ensureRootIsScheduled(root, eventTime);2379 schedulePendingInteractions(root, SyncLane);2380 }2381}2382export function captureCommitPhaseError(2383 sourceFiber: Fiber,2384 nearestMountedAncestor: Fiber | null,2385 error: mixed,2386) {2387 if (sourceFiber.tag === HostRoot) {2388 // Error was thrown at the root. There is no parent, so the root2389 // itself should capture it.2390 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);2391 return;2392 }2393 let fiber = null;2394 if (skipUnmountedBoundaries) {2395 fiber = nearestMountedAncestor;2396 } else {2397 fiber = sourceFiber.return;2398 }2399 while (fiber !== null) {2400 if (fiber.tag === HostRoot) {2401 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);2402 return;2403 } else if (fiber.tag === ClassComponent) {2404 const ctor = fiber.type;2405 const instance = fiber.stateNode;2406 if (2407 typeof ctor.getDerivedStateFromError === 'function' ||2408 (typeof instance.componentDidCatch === 'function' &&2409 !isAlreadyFailedLegacyErrorBoundary(instance))2410 ) {2411 const errorInfo = createCapturedValue(error, sourceFiber);2412 const update = createClassErrorUpdate(2413 fiber,2414 errorInfo,2415 (SyncLane: Lane),2416 );2417 enqueueUpdate(fiber, update);2418 const eventTime = requestEventTime();2419 const root = markUpdateLaneFromFiberToRoot(fiber, (SyncLane: Lane));2420 if (root !== null) {2421 markRootUpdated(root, SyncLane, eventTime);2422 ensureRootIsScheduled(root, eventTime);2423 schedulePendingInteractions(root, SyncLane);2424 }2425 return;2426 }2427 }2428 fiber = fiber.return;2429 }2430}2431export function pingSuspendedRoot(2432 root: FiberRoot,2433 wakeable: Wakeable,2434 pingedLanes: Lanes,2435) {2436 const pingCache = root.pingCache;2437 if (pingCache !== null) {2438 // The wakeable resolved, so we no longer need to memoize, because it will2439 // never be thrown again.2440 pingCache.delete(wakeable);2441 }2442 const eventTime = requestEventTime();2443 markRootPinged(root, pingedLanes, eventTime);2444 if (2445 workInProgressRoot === root &&2446 isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)2447 ) {2448 // Received a ping at the same priority level at which we're currently2449 // rendering. We might want to restart this render. This should mirror2450 // the logic of whether or not a root suspends once it completes.2451 // TODO: If we're rendering sync either due to Sync, Batched or expired,2452 // we should probably never restart.2453 // If we're suspended with delay, or if it's a retry, we'll always suspend2454 // so we can always restart.2455 if (2456 workInProgressRootExitStatus === RootSuspendedWithDelay ||2457 (workInProgressRootExitStatus === RootSuspended &&2458 includesOnlyRetries(workInProgressRootRenderLanes) &&2459 now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)2460 ) {2461 // Restart from the root.2462 prepareFreshStack(root, NoLanes);2463 } else {2464 // Even though we can't restart right now, we might get an2465 // opportunity later. So we mark this render as having a ping.2466 workInProgressRootPingedLanes = mergeLanes(2467 workInProgressRootPingedLanes,2468 pingedLanes,2469 );2470 }2471 }2472 ensureRootIsScheduled(root, eventTime);2473 schedulePendingInteractions(root, pingedLanes);2474}2475function retryTimedOutBoundary(boundaryFiber: Fiber, retryLane: Lane) {2476 // The boundary fiber (a Suspense component or SuspenseList component)2477 // previously was rendered in its fallback state. One of the promises that2478 // suspended it has resolved, which means at least part of the tree was2479 // likely unblocked. Try rendering again, at a new expiration time.2480 if (retryLane === NoLane) {2481 retryLane = requestRetryLane(boundaryFiber);2482 }2483 // TODO: Special case idle priority?2484 const eventTime = requestEventTime();2485 const root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);2486 if (root !== null) {2487 markRootUpdated(root, retryLane, eventTime);2488 ensureRootIsScheduled(root, eventTime);2489 schedulePendingInteractions(root, retryLane);2490 }2491}2492export function retryDehydratedSuspenseBoundary(boundaryFiber: Fiber) {2493 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2494 let retryLane = NoLane;2495 if (suspenseState !== null) {2496 retryLane = suspenseState.retryLane;2497 }2498 retryTimedOutBoundary(boundaryFiber, retryLane);2499}2500export function resolveRetryWakeable(boundaryFiber: Fiber, wakeable: Wakeable) {2501 let retryLane = NoLane; // Default2502 let retryCache: WeakSet<Wakeable> | Set<Wakeable> | null;2503 if (enableSuspenseServerRenderer) {2504 switch (boundaryFiber.tag) {2505 case SuspenseComponent:2506 retryCache = boundaryFiber.stateNode;2507 const suspenseState: null | SuspenseState = boundaryFiber.memoizedState;2508 if (suspenseState !== null) {2509 retryLane = suspenseState.retryLane;2510 }2511 break;2512 case SuspenseListComponent:2513 retryCache = boundaryFiber.stateNode;2514 break;2515 default:2516 invariant(2517 false,2518 'Pinged unknown suspense boundary type. ' +2519 'This is probably a bug in React.',2520 );2521 }2522 } else {2523 retryCache = boundaryFiber.stateNode;2524 }2525 if (retryCache !== null) {2526 // The wakeable resolved, so we no longer need to memoize, because it will2527 // never be thrown again.2528 retryCache.delete(wakeable);2529 }2530 retryTimedOutBoundary(boundaryFiber, retryLane);2531}2532// Computes the next Just Noticeable Difference (JND) boundary.2533// The theory is that a person can't tell the difference between small differences in time.2534// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable2535// difference in the experience. However, waiting for longer might mean that we can avoid2536// showing an intermediate loading state. The longer we have already waited, the harder it2537// is to tell small differences in time. Therefore, the longer we've already waited,2538// the longer we can wait additionally. At some point we have to give up though.2539// We pick a train model where the next boundary commits at a consistent schedule.2540// These particular numbers are vague estimates. We expect to adjust them based on research.2541function jnd(timeElapsed: number) {2542 return timeElapsed < 1202543 ? 1202544 : timeElapsed < 4802545 ? 4802546 : timeElapsed < 10802547 ? 10802548 : timeElapsed < 19202549 ? 19202550 : timeElapsed < 30002551 ? 30002552 : timeElapsed < 43202553 ? 43202554 : ceil(timeElapsed / 1960) * 1960;2555}2556function checkForNestedUpdates() {2557 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {2558 nestedUpdateCount = 0;2559 rootWithNestedUpdates = null;2560 invariant(2561 false,2562 'Maximum update depth exceeded. This can happen when a component ' +2563 'repeatedly calls setState inside componentWillUpdate or ' +2564 'componentDidUpdate. React limits the number of nested updates to ' +2565 'prevent infinite loops.',2566 );2567 }2568 if (__DEV__) {2569 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {2570 nestedPassiveUpdateCount = 0;2571 console.error(2572 'Maximum update depth exceeded. This can happen when a component ' +2573 "calls setState inside useEffect, but useEffect either doesn't " +2574 'have a dependency array, or one of the dependencies changes on ' +2575 'every render.',2576 );2577 }2578 }2579}2580function flushRenderPhaseStrictModeWarningsInDEV() {2581 if (__DEV__) {2582 ReactStrictModeWarnings.flushLegacyContextWarning();2583 if (warnAboutDeprecatedLifecycles) {2584 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();2585 }2586 }2587}2588function commitDoubleInvokeEffectsInDEV(2589 fiber: Fiber,2590 hasPassiveEffects: boolean,2591) {2592 if (__DEV__ && enableDoubleInvokingEffects) {2593 setCurrentDebugFiberInDEV(fiber);2594 invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectUnmountInDEV);2595 if (hasPassiveEffects) {2596 invokeEffectsInDev(2597 fiber,2598 MountPassiveDev,2599 invokePassiveEffectUnmountInDEV,2600 );2601 }2602 invokeEffectsInDev(fiber, MountLayoutDev, invokeLayoutEffectMountInDEV);2603 if (hasPassiveEffects) {2604 invokeEffectsInDev(fiber, MountPassiveDev, invokePassiveEffectMountInDEV);2605 }2606 resetCurrentDebugFiberInDEV();2607 }2608}2609function invokeEffectsInDev(2610 firstChild: Fiber,2611 fiberFlags: Flags,2612 invokeEffectFn: (fiber: Fiber) => void,2613): void {2614 if (__DEV__ && enableDoubleInvokingEffects) {2615 let fiber = firstChild;2616 while (fiber !== null) {2617 if (fiber.child !== null) {2618 const primarySubtreeFlag = fiber.subtreeFlags & fiberFlags;2619 if (primarySubtreeFlag !== NoFlags) {2620 invokeEffectsInDev(fiber.child, fiberFlags, invokeEffectFn);2621 }2622 }2623 if ((fiber.flags & fiberFlags) !== NoFlags) {2624 invokeEffectFn(fiber);2625 }2626 fiber = fiber.sibling;2627 }2628 }2629}2630let didWarnStateUpdateForNotYetMountedComponent: Set<string> | null = null;2631function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {2632 if (__DEV__) {2633 if ((executionContext & RenderContext) !== NoContext) {2634 // We let the other warning about render phase updates deal with this one.2635 return;2636 }2637 if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {2638 return;2639 }2640 const tag = fiber.tag;2641 if (2642 tag !== IndeterminateComponent &&2643 tag !== HostRoot &&2644 tag !== ClassComponent &&2645 tag !== FunctionComponent &&2646 tag !== ForwardRef &&2647 tag !== MemoComponent &&2648 tag !== SimpleMemoComponent &&2649 tag !== Block2650 ) {2651 // Only warn for user-defined components, not internal ones like Suspense.2652 return;2653 }2654 // We show the whole stack but dedupe on the top component's name because2655 // the problematic code almost always lies inside that component.2656 const componentName = getComponentName(fiber.type) || 'ReactComponent';2657 if (didWarnStateUpdateForNotYetMountedComponent !== null) {2658 if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {2659 return;2660 }2661 didWarnStateUpdateForNotYetMountedComponent.add(componentName);2662 } else {2663 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);2664 }2665 const previousFiber = ReactCurrentFiberCurrent;2666 try {2667 setCurrentDebugFiberInDEV(fiber);2668 console.error(2669 "Can't perform a React state update on a component that hasn't mounted yet. " +2670 'This indicates that you have a side-effect in your render function that ' +2671 'asynchronously later calls tries to update the component. Move this work to ' +2672 'useEffect instead.',2673 );2674 } finally {2675 if (previousFiber) {2676 setCurrentDebugFiberInDEV(fiber);2677 } else {2678 resetCurrentDebugFiberInDEV();2679 }2680 }2681 }2682}2683let didWarnStateUpdateForUnmountedComponent: Set<string> | null = null;2684function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {2685 if (__DEV__) {2686 const tag = fiber.tag;2687 if (2688 tag !== HostRoot &&2689 tag !== ClassComponent &&2690 tag !== FunctionComponent &&2691 tag !== ForwardRef &&2692 tag !== MemoComponent &&2693 tag !== SimpleMemoComponent &&2694 tag !== Block2695 ) {2696 // Only warn for user-defined components, not internal ones like Suspense.2697 return;2698 }2699 if ((fiber.flags & PassiveStatic) !== NoFlags) {2700 const updateQueue: FunctionComponentUpdateQueue | null = (fiber.updateQueue: any);2701 if (updateQueue !== null) {2702 const lastEffect = updateQueue.lastEffect;2703 if (lastEffect !== null) {2704 const firstEffect = lastEffect.next;2705 let effect = firstEffect;2706 do {2707 if (effect.destroy !== undefined) {2708 if ((effect.tag & HookPassive) !== NoHookEffect) {2709 return;2710 }2711 }2712 effect = effect.next;2713 } while (effect !== firstEffect);2714 }2715 }2716 }2717 // We show the whole stack but dedupe on the top component's name because2718 // the problematic code almost always lies inside that component.2719 const componentName = getComponentName(fiber.type) || 'ReactComponent';2720 if (didWarnStateUpdateForUnmountedComponent !== null) {2721 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {2722 return;2723 }2724 didWarnStateUpdateForUnmountedComponent.add(componentName);2725 } else {2726 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);2727 }2728 if (isFlushingPassiveEffects) {2729 // Do not warn if we are currently flushing passive effects!2730 //2731 // React can't directly detect a memory leak, but there are some clues that warn about one.2732 // One of these clues is when an unmounted React component tries to update its state.2733 // For example, if a component forgets to remove an event listener when unmounting,2734 // that listener may be called later and try to update state,2735 // at which point React would warn about the potential leak.2736 //2737 // Warning signals are the most useful when they're strong.2738 // (So we should avoid false positive warnings.)2739 // Updating state from within an effect cleanup function is sometimes a necessary pattern, e.g.:2740 // 1. Updating an ancestor that a component had registered itself with on mount.2741 // 2. Resetting state when a component is hidden after going offscreen.2742 } else {2743 const previousFiber = ReactCurrentFiberCurrent;2744 try {2745 setCurrentDebugFiberInDEV(fiber);2746 console.error(2747 "Can't perform a React state update on an unmounted component. This " +2748 'is a no-op, but it indicates a memory leak in your application. To ' +2749 'fix, cancel all subscriptions and asynchronous tasks in %s.',2750 tag === ClassComponent2751 ? 'the componentWillUnmount method'2752 : 'a useEffect cleanup function',2753 );2754 } finally {2755 if (previousFiber) {2756 setCurrentDebugFiberInDEV(fiber);2757 } else {2758 resetCurrentDebugFiberInDEV();2759 }2760 }2761 }2762 }2763}2764let beginWork;2765if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {2766 const dummyFiber = null;2767 beginWork = (current, unitOfWork, lanes) => {2768 // If a component throws an error, we replay it again in a synchronously2769 // dispatched event, so that the debugger will treat it as an uncaught2770 // error See ReactErrorUtils for more information.2771 // Before entering the begin phase, copy the work-in-progress onto a dummy2772 // fiber. If beginWork throws, we'll use this to reset the state.2773 const originalWorkInProgressCopy = assignFiberPropertiesInDEV(2774 dummyFiber,2775 unitOfWork,2776 );2777 try {2778 return originalBeginWork(current, unitOfWork, lanes);2779 } catch (originalError) {2780 if (2781 originalError !== null &&2782 typeof originalError === 'object' &&2783 typeof originalError.then === 'function'2784 ) {2785 // Don't replay promises. Treat everything else like an error.2786 throw originalError;2787 }2788 // Keep this code in sync with handleError; any changes here must have2789 // corresponding changes there.2790 resetContextDependencies();2791 resetHooksAfterThrow();2792 // Don't reset current debug fiber, since we're about to work on the2793 // same fiber again.2794 // Unwind the failed stack frame2795 unwindInterruptedWork(unitOfWork);2796 // Restore the original properties of the fiber.2797 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);2798 if (enableProfilerTimer && unitOfWork.mode & ProfileMode) {2799 // Reset the profiler timer.2800 startProfilerTimer(unitOfWork);2801 }2802 // Run beginWork again.2803 invokeGuardedCallback(2804 null,2805 originalBeginWork,2806 null,2807 current,2808 unitOfWork,2809 lanes,2810 );2811 if (hasCaughtError()) {2812 const replayError = clearCaughtError();2813 // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.2814 // Rethrow this error instead of the original one.2815 throw replayError;2816 } else {2817 // This branch is reachable if the render phase is impure.2818 throw originalError;2819 }2820 }2821 };2822} else {2823 beginWork = originalBeginWork;2824}2825let didWarnAboutUpdateInRender = false;2826let didWarnAboutUpdateInRenderForAnotherComponent;2827if (__DEV__) {2828 didWarnAboutUpdateInRenderForAnotherComponent = new Set();2829}2830function warnAboutRenderPhaseUpdatesInDEV(fiber) {2831 if (__DEV__) {2832 if (2833 ReactCurrentDebugFiberIsRenderingInDEV &&2834 (executionContext & RenderContext) !== NoContext &&2835 !getIsUpdatingOpaqueValueInRenderPhaseInDEV()2836 ) {2837 switch (fiber.tag) {2838 case FunctionComponent:2839 case ForwardRef:2840 case SimpleMemoComponent: {2841 const renderingComponentName =2842 (workInProgress && getComponentName(workInProgress.type)) ||2843 'Unknown';2844 // Dedupe by the rendering component because it's the one that needs to be fixed.2845 const dedupeKey = renderingComponentName;2846 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2847 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2848 const setStateComponentName =2849 getComponentName(fiber.type) || 'Unknown';2850 console.error(2851 'Cannot update a component (`%s`) while rendering a ' +2852 'different component (`%s`). To locate the bad setState() call inside `%s`, ' +2853 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render',2854 setStateComponentName,2855 renderingComponentName,2856 renderingComponentName,2857 );2858 }2859 break;2860 }2861 case ClassComponent: {2862 if (!didWarnAboutUpdateInRender) {2863 console.error(2864 'Cannot update during an existing state transition (such as ' +2865 'within `render`). Render methods should be a pure ' +2866 'function of props and state.',2867 );2868 didWarnAboutUpdateInRender = true;2869 }2870 break;2871 }2872 }2873 }2874 }2875}2876// a 'shared' variable that changes when act() opens/closes in tests.2877export const IsThisRendererActing = {current: (false: boolean)};2878export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {2879 if (__DEV__) {2880 if (2881 warnsIfNotActing === true &&2882 IsSomeRendererActing.current === true &&2883 IsThisRendererActing.current !== true2884 ) {2885 const previousFiber = ReactCurrentFiberCurrent;2886 try {2887 setCurrentDebugFiberInDEV(fiber);2888 console.error(2889 "It looks like you're using the wrong act() around your test interactions.\n" +2890 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' +2891 '// for react-dom:\n' +2892 // Break up imports to avoid accidentally parsing them as dependencies.2893 'import {act} fr' +2894 "om 'react-dom/test-utils';\n" +2895 '// ...\n' +2896 'act(() => ...);\n\n' +2897 '// for react-test-renderer:\n' +2898 // Break up imports to avoid accidentally parsing them as dependencies.2899 'import TestRenderer fr' +2900 "om react-test-renderer';\n" +2901 'const {act} = TestRenderer;\n' +2902 '// ...\n' +2903 'act(() => ...);',2904 );2905 } finally {2906 if (previousFiber) {2907 setCurrentDebugFiberInDEV(fiber);2908 } else {2909 resetCurrentDebugFiberInDEV();2910 }2911 }2912 }2913 }2914}2915export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {2916 if (__DEV__) {2917 if (2918 warnsIfNotActing === true &&2919 (fiber.mode & StrictMode) !== NoMode &&2920 IsSomeRendererActing.current === false &&2921 IsThisRendererActing.current === false2922 ) {2923 console.error(2924 'An update to %s ran an effect, but was not wrapped in act(...).\n\n' +2925 'When testing, code that causes React state updates should be ' +2926 'wrapped into act(...):\n\n' +2927 'act(() => {\n' +2928 ' /* fire events that update state */\n' +2929 '});\n' +2930 '/* assert on the output */\n\n' +2931 "This ensures that you're testing the behavior the user would see " +2932 'in the browser.' +2933 ' Learn more at https://reactjs.org/link/wrap-tests-with-act',2934 getComponentName(fiber.type),2935 );2936 }2937 }2938}2939function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {2940 if (__DEV__) {2941 if (2942 warnsIfNotActing === true &&2943 executionContext === NoContext &&2944 IsSomeRendererActing.current === false &&2945 IsThisRendererActing.current === false2946 ) {2947 const previousFiber = ReactCurrentFiberCurrent;2948 try {2949 setCurrentDebugFiberInDEV(fiber);2950 console.error(2951 'An update to %s inside a test was not wrapped in act(...).\n\n' +2952 'When testing, code that causes React state updates should be ' +2953 'wrapped into act(...):\n\n' +2954 'act(() => {\n' +2955 ' /* fire events that update state */\n' +2956 '});\n' +2957 '/* assert on the output */\n\n' +2958 "This ensures that you're testing the behavior the user would see " +2959 'in the browser.' +2960 ' Learn more at https://reactjs.org/link/wrap-tests-with-act',2961 getComponentName(fiber.type),2962 );2963 } finally {2964 if (previousFiber) {2965 setCurrentDebugFiberInDEV(fiber);2966 } else {2967 resetCurrentDebugFiberInDEV();2968 }2969 }2970 }2971 }2972}2973export const warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV;2974// In tests, we want to enforce a mocked scheduler.2975let didWarnAboutUnmockedScheduler = false;2976// TODO Before we release concurrent mode, revisit this and decide whether a mocked2977// scheduler is the actual recommendation. The alternative could be a testing build,2978// a new lib, or whatever; we dunno just yet. This message is for early adopters2979// to get their tests right.2980export function warnIfUnmockedScheduler(fiber: Fiber) {2981 if (__DEV__) {2982 if (2983 didWarnAboutUnmockedScheduler === false &&2984 Scheduler.unstable_flushAllWithoutAsserting === undefined2985 ) {2986 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2987 didWarnAboutUnmockedScheduler = true;2988 console.error(2989 'In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' +2990 'to guarantee consistent behaviour across tests and browsers. ' +2991 'For example, with jest: \n' +2992 // Break up requires to avoid accidentally parsing them as dependencies.2993 "jest.mock('scheduler', () => require" +2994 "('scheduler/unstable_mock'));\n\n" +2995 'For more info, visit https://reactjs.org/link/mock-scheduler',2996 );2997 } else if (warnAboutUnmockedScheduler === true) {2998 didWarnAboutUnmockedScheduler = true;2999 console.error(3000 'Starting from React v18, the "scheduler" module will need to be mocked ' +3001 'to guarantee consistent behaviour across tests and browsers. ' +3002 'For example, with jest: \n' +3003 // Break up requires to avoid accidentally parsing them as dependencies.3004 "jest.mock('scheduler', () => require" +3005 "('scheduler/unstable_mock'));\n\n" +3006 'For more info, visit https://reactjs.org/link/mock-scheduler',3007 );3008 }3009 }3010 }3011}3012function computeThreadID(root: FiberRoot, lane: Lane | Lanes) {3013 // Interaction threads are unique per root and expiration time.3014 // NOTE: Intentionally unsound cast. All that matters is that it's a number3015 // and it represents a batch of work. Could make a helper function instead,3016 // but meh this is fine for now.3017 return (lane: any) * 1000 + root.interactionThreadID;3018}3019export function markSpawnedWork(lane: Lane | Lanes) {3020 if (!enableSchedulerTracing) {3021 return;3022 }3023 if (spawnedWorkDuringRender === null) {3024 spawnedWorkDuringRender = [lane];3025 } else {3026 spawnedWorkDuringRender.push(lane);3027 }3028}3029function scheduleInteractions(3030 root: FiberRoot,3031 lane: Lane | Lanes,3032 interactions: Set<Interaction>,3033) {3034 if (!enableSchedulerTracing) {3035 return;3036 }3037 if (interactions.size > 0) {3038 const pendingInteractionMap = root.pendingInteractionMap;3039 const pendingInteractions = pendingInteractionMap.get(lane);3040 if (pendingInteractions != null) {3041 interactions.forEach(interaction => {3042 if (!pendingInteractions.has(interaction)) {3043 // Update the pending async work count for previously unscheduled interaction.3044 interaction.__count++;3045 }3046 pendingInteractions.add(interaction);3047 });3048 } else {3049 pendingInteractionMap.set(lane, new Set(interactions));3050 // Update the pending async work count for the current interactions.3051 interactions.forEach(interaction => {3052 interaction.__count++;3053 });3054 }3055 const subscriber = __subscriberRef.current;3056 if (subscriber !== null) {3057 const threadID = computeThreadID(root, lane);3058 subscriber.onWorkScheduled(interactions, threadID);3059 }3060 }3061}3062function schedulePendingInteractions(root: FiberRoot, lane: Lane | Lanes) {3063 // This is called when work is scheduled on a root.3064 // It associates the current interactions with the newly-scheduled expiration.3065 // They will be restored when that expiration is later committed.3066 if (!enableSchedulerTracing) {3067 return;3068 }3069 scheduleInteractions(root, lane, __interactionsRef.current);3070}3071function startWorkOnPendingInteractions(root: FiberRoot, lanes: Lanes) {3072 // This is called when new work is started on a root.3073 if (!enableSchedulerTracing) {3074 return;3075 }3076 // Determine which interactions this batch of work currently includes, So that3077 // we can accurately attribute time spent working on it, And so that cascading3078 // work triggered during the render phase will be associated with it.3079 const interactions: Set<Interaction> = new Set();3080 root.pendingInteractionMap.forEach((scheduledInteractions, scheduledLane) => {3081 if (includesSomeLane(lanes, scheduledLane)) {3082 scheduledInteractions.forEach(interaction =>3083 interactions.add(interaction),...
ReactFiberWorkLoop.old.js
Source:ReactFiberWorkLoop.old.js
...1346 if (spawnedWorkDuringRender !== null) {1347 var expirationTimes = spawnedWorkDuringRender;1348 spawnedWorkDuringRender = null;1349 for (var i = 0; i < expirationTimes.length; i++) {1350 scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);1351 }1352 }1353 schedulePendingInteractions(root, remainingLanes);1354 }1355 } else {1356 // If there's no remaining work, we can clear the set of already failed1357 // error boundaries.1358 legacyErrorBoundariesThatAlreadyFailed = null;1359 }1360 {1361 if (!rootDidHavePassiveEffects) {1362 // If there are no passive effects, then we can complete the pending interactions.1363 // Otherwise, we'll wait until after the passive effects are flushed.1364 // Wait to do this until after remaining work has been scheduled,1365 // so that we don't prematurely signal complete for interactions when there's e.g. hidden work.1366 finishPendingInteractions(root, lanes);1367 }1368 }1369 if (remainingLanes === SyncLane) {1370 // Count the number of times the root synchronously re-renders without1371 // finishing. If there are too many, it indicates an infinite update loop.1372 if (root === rootWithNestedUpdates) {1373 nestedUpdateCount++;1374 } else {1375 nestedUpdateCount = 0;1376 rootWithNestedUpdates = root;1377 }1378 } else {1379 nestedUpdateCount = 0;1380 }1381 onCommitRoot(finishedWork.stateNode, renderPriorityLevel);1382 {1383 onCommitRoot$1();1384 } // Always call this before exiting `commitRoot`, to ensure that any1385 // additional work on this root is scheduled.1386 ensureRootIsScheduled(root, now());1387 if (hasUncaughtError) {1388 hasUncaughtError = false;1389 var _error3 = firstUncaughtError;1390 firstUncaughtError = null;1391 throw _error3;1392 }1393 if ((executionContext & LegacyUnbatchedContext) !== NoContext) {1394 {1395 markCommitStopped();1396 } // This is a legacy edge case. We just committed the initial mount of1397 // a ReactDOM.render-ed root inside of batchedUpdates. The commit fired1398 // synchronously, but layout updates should be deferred until the end1399 // of the batch.1400 return null;1401 } // If layout work was scheduled, flush it now.1402 flushSyncCallbackQueue();1403 {1404 markCommitStopped();1405 }1406 return null;1407 }1408 function commitBeforeMutationEffects() {1409 while (nextEffect !== null) {1410 var current = nextEffect.alternate;1411 if (!shouldFireAfterActiveInstanceBlur && focusedInstanceHandle !== null) {1412 if ((nextEffect.flags & Deletion) !== NoFlags) {1413 if (doesFiberContain(nextEffect, focusedInstanceHandle)) {1414 shouldFireAfterActiveInstanceBlur = true;1415 }1416 } else {1417 // TODO: Move this out of the hot path using a dedicated effect tag.1418 if (nextEffect.tag === SuspenseComponent && isSuspenseBoundaryBeingHidden(current, nextEffect) && doesFiberContain(nextEffect, focusedInstanceHandle)) {1419 shouldFireAfterActiveInstanceBlur = true;1420 }1421 }1422 }1423 var flags = nextEffect.flags;1424 if ((flags & Snapshot) !== NoFlags) {1425 setCurrentFiber(nextEffect);1426 commitBeforeMutationLifeCycles(current, nextEffect);1427 resetCurrentFiber();1428 }1429 if ((flags & Passive) !== NoFlags) {1430 // If there are passive effects, schedule a callback to flush at1431 // the earliest opportunity.1432 if (!rootDoesHavePassiveEffects) {1433 rootDoesHavePassiveEffects = true;1434 scheduleCallback(NormalPriority$1, function () {1435 flushPassiveEffects();1436 return null;1437 });1438 }1439 }1440 nextEffect = nextEffect.nextEffect;1441 }1442 }1443 function commitMutationEffects(root, renderPriorityLevel) {1444 // TODO: Should probably move the bulk of this function to commitWork.1445 while (nextEffect !== null) {1446 setCurrentFiber(nextEffect);1447 var flags = nextEffect.flags;1448 if (flags & ContentReset) {1449 commitResetTextContent(nextEffect);1450 }1451 if (flags & Ref) {1452 var current = nextEffect.alternate;1453 if (current !== null) {1454 commitDetachRef(current);1455 }1456 } // The following switch statement is only concerned about placement,1457 // updates, and deletions. To avoid needing to add a case for every possible1458 // bitmap value, we remove the secondary effects from the effect tag and1459 // switch on that value.1460 var primaryFlags = flags & (Placement | Update | Deletion | Hydrating);1461 switch (primaryFlags) {1462 case Placement:1463 {1464 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1465 // inserted, before any life-cycles like componentDidMount gets called.1466 // TODO: findDOMNode doesn't rely on this any more but isMounted does1467 // and isMounted is deprecated anyway so we should be able to kill this.1468 nextEffect.flags &= ~Placement;1469 break;1470 }1471 case PlacementAndUpdate:1472 {1473 // Placement1474 commitPlacement(nextEffect); // Clear the "placement" from effect tag so that we know that this is1475 // inserted, before any life-cycles like componentDidMount gets called.1476 nextEffect.flags &= ~Placement; // Update1477 var _current = nextEffect.alternate;1478 commitWork(_current, nextEffect);1479 break;1480 }1481 case Hydrating:1482 {1483 nextEffect.flags &= ~Hydrating;1484 break;1485 }1486 case HydratingAndUpdate:1487 {1488 nextEffect.flags &= ~Hydrating; // Update1489 var _current2 = nextEffect.alternate;1490 commitWork(_current2, nextEffect);1491 break;1492 }1493 case Update:1494 {1495 var _current3 = nextEffect.alternate;1496 commitWork(_current3, nextEffect);1497 break;1498 }1499 case Deletion:1500 {1501 commitDeletion(root, nextEffect);1502 break;1503 }1504 }1505 resetCurrentFiber();1506 nextEffect = nextEffect.nextEffect;1507 }1508 }1509 function commitLayoutEffects(root, committedLanes) {1510 {1511 markLayoutEffectsStarted(committedLanes);1512 } // TODO: Should probably move the bulk of this function to commitWork.1513 while (nextEffect !== null) {1514 setCurrentFiber(nextEffect);1515 var flags = nextEffect.flags;1516 if (flags & (Update | Callback)) {1517 var current = nextEffect.alternate;1518 commitLifeCycles(root, current, nextEffect);1519 }1520 {1521 if (flags & Ref) {1522 commitAttachRef(nextEffect);1523 }1524 }1525 resetCurrentFiber();1526 nextEffect = nextEffect.nextEffect;1527 }1528 {1529 markLayoutEffectsStopped();1530 }1531 }1532 function flushPassiveEffects() {1533 // Returns whether passive effects were flushed.1534 if (pendingPassiveEffectsRenderPriority !== NoPriority$1) {1535 var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority$1 ? NormalPriority$1 : pendingPassiveEffectsRenderPriority;1536 pendingPassiveEffectsRenderPriority = NoPriority$1;1537 {1538 return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);1539 }1540 }1541 return false;1542 }1543 function enqueuePendingPassiveHookEffectMount(fiber, effect) {1544 pendingPassiveHookEffectsMount.push(effect, fiber);1545 if (!rootDoesHavePassiveEffects) {1546 rootDoesHavePassiveEffects = true;1547 scheduleCallback(NormalPriority$1, function () {1548 flushPassiveEffects();1549 return null;1550 });1551 }1552 }1553 function enqueuePendingPassiveHookEffectUnmount(fiber, effect) {1554 pendingPassiveHookEffectsUnmount.push(effect, fiber);1555 {1556 fiber.flags |= PassiveUnmountPendingDev;1557 var alternate = fiber.alternate;1558 if (alternate !== null) {1559 alternate.flags |= PassiveUnmountPendingDev;1560 }1561 }1562 if (!rootDoesHavePassiveEffects) {1563 rootDoesHavePassiveEffects = true;1564 scheduleCallback(NormalPriority$1, function () {1565 flushPassiveEffects();1566 return null;1567 });1568 }1569 }1570 function invokePassiveEffectCreate(effect) {1571 var create = effect.create;1572 effect.destroy = create();1573 }1574 function flushPassiveEffectsImpl() {1575 if (rootWithPendingPassiveEffects === null) {1576 return false;1577 }1578 var root = rootWithPendingPassiveEffects;1579 var lanes = pendingPassiveEffectsLanes;1580 rootWithPendingPassiveEffects = null;1581 pendingPassiveEffectsLanes = NoLanes;1582 if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {1583 {1584 throw Error( "Cannot flush passive effects while already rendering." );1585 }1586 }1587 {1588 markPassiveEffectsStarted(lanes);1589 }1590 {1591 isFlushingPassiveEffects = true;1592 }1593 var prevExecutionContext = executionContext;1594 executionContext |= CommitContext;1595 var prevInteractions = pushInteractions(root); // It's important that ALL pending passive effect destroy functions are called1596 // before ANY passive effect create functions are called.1597 // Otherwise effects in sibling components might interfere with each other.1598 // e.g. a destroy function in one component may unintentionally override a ref1599 // value set by a create function in another component.1600 // Layout effects have the same constraint.1601 // First pass: Destroy stale passive effects.1602 var unmountEffects = pendingPassiveHookEffectsUnmount;1603 pendingPassiveHookEffectsUnmount = [];1604 for (var i = 0; i < unmountEffects.length; i += 2) {1605 var _effect = unmountEffects[i];1606 var fiber = unmountEffects[i + 1];1607 var destroy = _effect.destroy;1608 _effect.destroy = undefined;1609 {1610 fiber.flags &= ~PassiveUnmountPendingDev;1611 var alternate = fiber.alternate;1612 if (alternate !== null) {1613 alternate.flags &= ~PassiveUnmountPendingDev;1614 }1615 }1616 if (typeof destroy === 'function') {1617 {1618 setCurrentFiber(fiber);1619 {1620 invokeGuardedCallback(null, destroy, null);1621 }1622 if (hasCaughtError()) {1623 if (!(fiber !== null)) {1624 {1625 throw Error( "Should be working on an effect." );1626 }1627 }1628 var error = clearCaughtError();1629 captureCommitPhaseError(fiber, error);1630 }1631 resetCurrentFiber();1632 }1633 }1634 } // Second pass: Create new passive effects.1635 var mountEffects = pendingPassiveHookEffectsMount;1636 pendingPassiveHookEffectsMount = [];1637 for (var _i = 0; _i < mountEffects.length; _i += 2) {1638 var _effect2 = mountEffects[_i];1639 var _fiber = mountEffects[_i + 1];1640 {1641 setCurrentFiber(_fiber);1642 {1643 invokeGuardedCallback(null, invokePassiveEffectCreate, null, _effect2);1644 }1645 if (hasCaughtError()) {1646 if (!(_fiber !== null)) {1647 {1648 throw Error( "Should be working on an effect." );1649 }1650 }1651 var _error4 = clearCaughtError();1652 captureCommitPhaseError(_fiber, _error4);1653 }1654 resetCurrentFiber();1655 }1656 } // Note: This currently assumes there are no passive effects on the root fiber1657 // because the root is not part of its own effect list.1658 // This could change in the future.1659 var effect = root.current.firstEffect;1660 while (effect !== null) {1661 var nextNextEffect = effect.nextEffect; // Remove nextEffect pointer to assist GC1662 effect.nextEffect = null;1663 if (effect.flags & Deletion) {1664 detachFiberAfterEffects(effect);1665 }1666 effect = nextNextEffect;1667 }1668 {1669 popInteractions(prevInteractions);1670 finishPendingInteractions(root, lanes);1671 }1672 {1673 isFlushingPassiveEffects = false;1674 }1675 {1676 markPassiveEffectsStopped();1677 }1678 executionContext = prevExecutionContext;1679 flushSyncCallbackQueue(); // If additional passive effects were scheduled, increment a counter. If this1680 // exceeds the limit, we'll fire a warning.1681 nestedPassiveUpdateCount = rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;1682 return true;1683 }1684 function isAlreadyFailedLegacyErrorBoundary(instance) {1685 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance);1686 }1687 function markLegacyErrorBoundaryAsFailed(instance) {1688 if (legacyErrorBoundariesThatAlreadyFailed === null) {1689 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]);1690 } else {1691 legacyErrorBoundariesThatAlreadyFailed.add(instance);1692 }1693 }1694 function prepareToThrowUncaughtError(error) {1695 if (!hasUncaughtError) {1696 hasUncaughtError = true;1697 firstUncaughtError = error;1698 }1699 }1700 var onUncaughtError = prepareToThrowUncaughtError;1701 function captureCommitPhaseErrorOnRoot(rootFiber, sourceFiber, error) {1702 var errorInfo = createCapturedValue(error, sourceFiber);1703 var update = createRootErrorUpdate(rootFiber, errorInfo, SyncLane);1704 enqueueUpdate(rootFiber, update);1705 var eventTime = requestEventTime();1706 var root = markUpdateLaneFromFiberToRoot(rootFiber, SyncLane);1707 if (root !== null) {1708 markRootUpdated(root, SyncLane, eventTime);1709 ensureRootIsScheduled(root, eventTime);1710 schedulePendingInteractions(root, SyncLane);1711 }1712 }1713 function captureCommitPhaseError(sourceFiber, error) {1714 if (sourceFiber.tag === HostRoot) {1715 // Error was thrown at the root. There is no parent, so the root1716 // itself should capture it.1717 captureCommitPhaseErrorOnRoot(sourceFiber, sourceFiber, error);1718 return;1719 }1720 var fiber = sourceFiber.return;1721 while (fiber !== null) {1722 if (fiber.tag === HostRoot) {1723 captureCommitPhaseErrorOnRoot(fiber, sourceFiber, error);1724 return;1725 } else if (fiber.tag === ClassComponent) {1726 var ctor = fiber.type;1727 var instance = fiber.stateNode;1728 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1729 var errorInfo = createCapturedValue(error, sourceFiber);1730 var update = createClassErrorUpdate(fiber, errorInfo, SyncLane);1731 enqueueUpdate(fiber, update);1732 var eventTime = requestEventTime();1733 var root = markUpdateLaneFromFiberToRoot(fiber, SyncLane);1734 if (root !== null) {1735 markRootUpdated(root, SyncLane, eventTime);1736 ensureRootIsScheduled(root, eventTime);1737 schedulePendingInteractions(root, SyncLane);1738 } else {1739 // This component has already been unmounted.1740 // We can't schedule any follow up work for the root because the fiber is already unmounted,1741 // but we can still call the log-only boundary so the error isn't swallowed.1742 //1743 // TODO This is only a temporary bandaid for the old reconciler fork.1744 // We can delete this special case once the new fork is merged.1745 if (typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) {1746 try {1747 instance.componentDidCatch(error, errorInfo);1748 } catch (errorToIgnore) {// TODO Ignore this error? Rethrow it?1749 // This is kind of an edge case.1750 }1751 }1752 }1753 return;1754 }1755 }1756 fiber = fiber.return;1757 }1758 }1759 function pingSuspendedRoot(root, wakeable, pingedLanes) {1760 var pingCache = root.pingCache;1761 if (pingCache !== null) {1762 // The wakeable resolved, so we no longer need to memoize, because it will1763 // never be thrown again.1764 pingCache.delete(wakeable);1765 }1766 var eventTime = requestEventTime();1767 markRootPinged(root, pingedLanes);1768 if (workInProgressRoot === root && isSubsetOfLanes(workInProgressRootRenderLanes, pingedLanes)) {1769 // Received a ping at the same priority level at which we're currently1770 // rendering. We might want to restart this render. This should mirror1771 // the logic of whether or not a root suspends once it completes.1772 // TODO: If we're rendering sync either due to Sync, Batched or expired,1773 // we should probably never restart.1774 // If we're suspended with delay, or if it's a retry, we'll always suspend1775 // so we can always restart.1776 if (workInProgressRootExitStatus === RootSuspendedWithDelay || workInProgressRootExitStatus === RootSuspended && includesOnlyRetries(workInProgressRootRenderLanes) && now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS) {1777 // Restart from the root.1778 prepareFreshStack(root, NoLanes);1779 } else {1780 // Even though we can't restart right now, we might get an1781 // opportunity later. So we mark this render as having a ping.1782 workInProgressRootPingedLanes = mergeLanes(workInProgressRootPingedLanes, pingedLanes);1783 }1784 }1785 ensureRootIsScheduled(root, eventTime);1786 schedulePendingInteractions(root, pingedLanes);1787 }1788 function retryTimedOutBoundary(boundaryFiber, retryLane) {1789 // The boundary fiber (a Suspense component or SuspenseList component)1790 // previously was rendered in its fallback state. One of the promises that1791 // suspended it has resolved, which means at least part of the tree was1792 // likely unblocked. Try rendering again, at a new expiration time.1793 if (retryLane === NoLane) {1794 retryLane = requestRetryLane(boundaryFiber);1795 } // TODO: Special case idle priority?1796 var eventTime = requestEventTime();1797 var root = markUpdateLaneFromFiberToRoot(boundaryFiber, retryLane);1798 if (root !== null) {1799 markRootUpdated(root, retryLane, eventTime);1800 ensureRootIsScheduled(root, eventTime);1801 schedulePendingInteractions(root, retryLane);1802 }1803 }1804 function retryDehydratedSuspenseBoundary(boundaryFiber) {1805 var suspenseState = boundaryFiber.memoizedState;1806 var retryLane = NoLane;1807 if (suspenseState !== null) {1808 retryLane = suspenseState.retryLane;1809 }1810 retryTimedOutBoundary(boundaryFiber, retryLane);1811 }1812 function resolveRetryWakeable(boundaryFiber, wakeable) {1813 var retryLane = NoLane; // Default1814 var retryCache;1815 {1816 switch (boundaryFiber.tag) {1817 case SuspenseComponent:1818 retryCache = boundaryFiber.stateNode;1819 var suspenseState = boundaryFiber.memoizedState;1820 if (suspenseState !== null) {1821 retryLane = suspenseState.retryLane;1822 }1823 break;1824 case SuspenseListComponent:1825 retryCache = boundaryFiber.stateNode;1826 break;1827 default:1828 {1829 {1830 throw Error( "Pinged unknown suspense boundary type. This is probably a bug in React." );1831 }1832 }1833 }1834 }1835 if (retryCache !== null) {1836 // The wakeable resolved, so we no longer need to memoize, because it will1837 // never be thrown again.1838 retryCache.delete(wakeable);1839 }1840 retryTimedOutBoundary(boundaryFiber, retryLane);1841 } // Computes the next Just Noticeable Difference (JND) boundary.1842 // The theory is that a person can't tell the difference between small differences in time.1843 // Therefore, if we wait a bit longer than necessary that won't translate to a noticeable1844 // difference in the experience. However, waiting for longer might mean that we can avoid1845 // showing an intermediate loading state. The longer we have already waited, the harder it1846 // is to tell small differences in time. Therefore, the longer we've already waited,1847 // the longer we can wait additionally. At some point we have to give up though.1848 // We pick a train model where the next boundary commits at a consistent schedule.1849 // These particular numbers are vague estimates. We expect to adjust them based on research.1850 function jnd(timeElapsed) {1851 return timeElapsed < 120 ? 120 : timeElapsed < 480 ? 480 : timeElapsed < 1080 ? 1080 : timeElapsed < 1920 ? 1920 : timeElapsed < 3000 ? 3000 : timeElapsed < 4320 ? 4320 : ceil(timeElapsed / 1960) * 1960;1852 }1853 function checkForNestedUpdates() {1854 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {1855 nestedUpdateCount = 0;1856 rootWithNestedUpdates = null;1857 {1858 {1859 throw Error( "Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops." );1860 }1861 }1862 }1863 {1864 if (nestedPassiveUpdateCount > NESTED_PASSIVE_UPDATE_LIMIT) {1865 nestedPassiveUpdateCount = 0;1866 error('Maximum update depth exceeded. This can happen when a component ' + "calls setState inside useEffect, but useEffect either doesn't " + 'have a dependency array, or one of the dependencies changes on ' + 'every render.');1867 }1868 }1869 }1870 function flushRenderPhaseStrictModeWarningsInDEV() {1871 {1872 ReactStrictModeWarnings.flushLegacyContextWarning();1873 {1874 ReactStrictModeWarnings.flushPendingUnsafeLifecycleWarnings();1875 }1876 }1877 }1878 var didWarnStateUpdateForNotYetMountedComponent = null;1879 function warnAboutUpdateOnNotYetMountedFiberInDEV(fiber) {1880 {1881 if ((executionContext & RenderContext) !== NoContext) {1882 // We let the other warning about render phase updates deal with this one.1883 return;1884 }1885 if (!(fiber.mode & (BlockingMode | ConcurrentMode))) {1886 return;1887 }1888 var tag = fiber.tag;1889 if (tag !== IndeterminateComponent && tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1890 // Only warn for user-defined components, not internal ones like Suspense.1891 return;1892 } // We show the whole stack but dedupe on the top component's name because1893 // the problematic code almost always lies inside that component.1894 var componentName = getComponentName(fiber.type) || 'ReactComponent';1895 if (didWarnStateUpdateForNotYetMountedComponent !== null) {1896 if (didWarnStateUpdateForNotYetMountedComponent.has(componentName)) {1897 return;1898 }1899 didWarnStateUpdateForNotYetMountedComponent.add(componentName);1900 } else {1901 didWarnStateUpdateForNotYetMountedComponent = new Set([componentName]);1902 }1903 var previousFiber = current;1904 try {1905 setCurrentFiber(fiber);1906 error("Can't perform a React state update on a component that hasn't mounted yet. " + 'This indicates that you have a side-effect in your render function that ' + 'asynchronously later calls tries to update the component. Move this work to ' + 'useEffect instead.');1907 } finally {1908 if (previousFiber) {1909 setCurrentFiber(fiber);1910 } else {1911 resetCurrentFiber();1912 }1913 }1914 }1915 }1916 var didWarnStateUpdateForUnmountedComponent = null;1917 function warnAboutUpdateOnUnmountedFiberInDEV(fiber) {1918 {1919 var tag = fiber.tag;1920 if (tag !== HostRoot && tag !== ClassComponent && tag !== FunctionComponent && tag !== ForwardRef && tag !== MemoComponent && tag !== SimpleMemoComponent && tag !== Block) {1921 // Only warn for user-defined components, not internal ones like Suspense.1922 return;1923 } // If there are pending passive effects unmounts for this Fiber,1924 // we can assume that they would have prevented this update.1925 if ((fiber.flags & PassiveUnmountPendingDev) !== NoFlags) {1926 return;1927 } // We show the whole stack but dedupe on the top component's name because1928 // the problematic code almost always lies inside that component.1929 var componentName = getComponentName(fiber.type) || 'ReactComponent';1930 if (didWarnStateUpdateForUnmountedComponent !== null) {1931 if (didWarnStateUpdateForUnmountedComponent.has(componentName)) {1932 return;1933 }1934 didWarnStateUpdateForUnmountedComponent.add(componentName);1935 } else {1936 didWarnStateUpdateForUnmountedComponent = new Set([componentName]);1937 }1938 if (isFlushingPassiveEffects) ; else {1939 var previousFiber = current;1940 try {1941 setCurrentFiber(fiber);1942 error("Can't perform a React state update on an unmounted component. This " + 'is a no-op, but it indicates a memory leak in your application. To ' + 'fix, cancel all subscriptions and asynchronous tasks in %s.', tag === ClassComponent ? 'the componentWillUnmount method' : 'a useEffect cleanup function');1943 } finally {1944 if (previousFiber) {1945 setCurrentFiber(fiber);1946 } else {1947 resetCurrentFiber();1948 }1949 }1950 }1951 }1952 }1953 var beginWork$1;1954 {1955 var dummyFiber = null;1956 beginWork$1 = function (current, unitOfWork, lanes) {1957 // If a component throws an error, we replay it again in a synchronously1958 // dispatched event, so that the debugger will treat it as an uncaught1959 // error See ReactErrorUtils for more information.1960 // Before entering the begin phase, copy the work-in-progress onto a dummy1961 // fiber. If beginWork throws, we'll use this to reset the state.1962 var originalWorkInProgressCopy = assignFiberPropertiesInDEV(dummyFiber, unitOfWork);1963 try {1964 return beginWork(current, unitOfWork, lanes);1965 } catch (originalError) {1966 if (originalError !== null && typeof originalError === 'object' && typeof originalError.then === 'function') {1967 // Don't replay promises. Treat everything else like an error.1968 throw originalError;1969 } // Keep this code in sync with handleError; any changes here must have1970 // corresponding changes there.1971 resetContextDependencies();1972 resetHooksAfterThrow(); // Don't reset current debug fiber, since we're about to work on the1973 // same fiber again.1974 // Unwind the failed stack frame1975 unwindInterruptedWork(unitOfWork); // Restore the original properties of the fiber.1976 assignFiberPropertiesInDEV(unitOfWork, originalWorkInProgressCopy);1977 if ( unitOfWork.mode & ProfileMode) {1978 // Reset the profiler timer.1979 startProfilerTimer(unitOfWork);1980 } // Run beginWork again.1981 invokeGuardedCallback(null, beginWork, null, current, unitOfWork, lanes);1982 if (hasCaughtError()) {1983 var replayError = clearCaughtError(); // `invokeGuardedCallback` sometimes sets an expando `_suppressLogging`.1984 // Rethrow this error instead of the original one.1985 throw replayError;1986 } else {1987 // This branch is reachable if the render phase is impure.1988 throw originalError;1989 }1990 }1991 };1992 }1993 var didWarnAboutUpdateInRender = false;1994 var didWarnAboutUpdateInRenderForAnotherComponent;1995 {1996 didWarnAboutUpdateInRenderForAnotherComponent = new Set();1997 }1998 function warnAboutRenderPhaseUpdatesInDEV(fiber) {1999 {2000 if (isRendering && (executionContext & RenderContext) !== NoContext && !getIsUpdatingOpaqueValueInRenderPhaseInDEV()) {2001 switch (fiber.tag) {2002 case FunctionComponent:2003 case ForwardRef:2004 case SimpleMemoComponent:2005 {2006 var renderingComponentName = workInProgress && getComponentName(workInProgress.type) || 'Unknown'; // Dedupe by the rendering component because it's the one that needs to be fixed.2007 var dedupeKey = renderingComponentName;2008 if (!didWarnAboutUpdateInRenderForAnotherComponent.has(dedupeKey)) {2009 didWarnAboutUpdateInRenderForAnotherComponent.add(dedupeKey);2010 var setStateComponentName = getComponentName(fiber.type) || 'Unknown';2011 error('Cannot update a component (`%s`) while rendering a ' + 'different component (`%s`). To locate the bad setState() call inside `%s`, ' + 'follow the stack trace as described in https://reactjs.org/link/setstate-in-render', setStateComponentName, renderingComponentName, renderingComponentName);2012 }2013 break;2014 }2015 case ClassComponent:2016 {2017 if (!didWarnAboutUpdateInRender) {2018 error('Cannot update during an existing state transition (such as ' + 'within `render`). Render methods should be a pure ' + 'function of props and state.');2019 didWarnAboutUpdateInRender = true;2020 }2021 break;2022 }2023 }2024 }2025 }2026 } // a 'shared' variable that changes when act() opens/closes in tests.2027 var IsThisRendererActing = {2028 current: false2029 };2030 function warnIfNotScopedWithMatchingAct(fiber) {2031 {2032 if ( IsSomeRendererActing.current === true && IsThisRendererActing.current !== true) {2033 var previousFiber = current;2034 try {2035 setCurrentFiber(fiber);2036 error("It looks like you're using the wrong act() around your test interactions.\n" + 'Be sure to use the matching version of act() corresponding to your renderer:\n\n' + '// for react-dom:\n' + // Break up imports to avoid accidentally parsing them as dependencies.2037 'import {act} fr' + "om 'react-dom/test-utils';\n" + '// ...\n' + 'act(() => ...);\n\n' + '// for react-test-renderer:\n' + // Break up imports to avoid accidentally parsing them as dependencies.2038 'import TestRenderer fr' + "om react-test-renderer';\n" + 'const {act} = TestRenderer;\n' + '// ...\n' + 'act(() => ...);');2039 } finally {2040 if (previousFiber) {2041 setCurrentFiber(fiber);2042 } else {2043 resetCurrentFiber();2044 }2045 }2046 }2047 }2048 }2049 function warnIfNotCurrentlyActingEffectsInDEV(fiber) {2050 {2051 if ( (fiber.mode & StrictMode) !== NoMode && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2052 error('An update to %s ran an effect, but was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));2053 }2054 }2055 }2056 function warnIfNotCurrentlyActingUpdatesInDEV(fiber) {2057 {2058 if ( executionContext === NoContext && IsSomeRendererActing.current === false && IsThisRendererActing.current === false) {2059 var previousFiber = current;2060 try {2061 setCurrentFiber(fiber);2062 error('An update to %s inside a test was not wrapped in act(...).\n\n' + 'When testing, code that causes React state updates should be ' + 'wrapped into act(...):\n\n' + 'act(() => {\n' + ' /* fire events that update state */\n' + '});\n' + '/* assert on the output */\n\n' + "This ensures that you're testing the behavior the user would see " + 'in the browser.' + ' Learn more at https://reactjs.org/link/wrap-tests-with-act', getComponentName(fiber.type));2063 } finally {2064 if (previousFiber) {2065 setCurrentFiber(fiber);2066 } else {2067 resetCurrentFiber();2068 }2069 }2070 }2071 }2072 }2073 var warnIfNotCurrentlyActingUpdatesInDev = warnIfNotCurrentlyActingUpdatesInDEV; // In tests, we want to enforce a mocked scheduler.2074 var didWarnAboutUnmockedScheduler = false; // TODO Before we release concurrent mode, revisit this and decide whether a mocked2075 // scheduler is the actual recommendation. The alternative could be a testing build,2076 // a new lib, or whatever; we dunno just yet. This message is for early adopters2077 // to get their tests right.2078 function warnIfUnmockedScheduler(fiber) {2079 {2080 if (didWarnAboutUnmockedScheduler === false && unstable_flushAllWithoutAsserting === undefined) {2081 if (fiber.mode & BlockingMode || fiber.mode & ConcurrentMode) {2082 didWarnAboutUnmockedScheduler = true;2083 error('In Concurrent or Sync modes, the "scheduler" module needs to be mocked ' + 'to guarantee consistent behaviour across tests and browsers. ' + 'For example, with jest: \n' + // Break up requires to avoid accidentally parsing them as dependencies.2084 "jest.mock('scheduler', () => require" + "('scheduler/unstable_mock'));\n\n" + 'For more info, visit https://reactjs.org/link/mock-scheduler');2085 }2086 }2087 }2088 }2089 function computeThreadID(root, lane) {2090 // Interaction threads are unique per root and expiration time.2091 // NOTE: Intentionally unsound cast. All that matters is that it's a number2092 // and it represents a batch of work. Could make a helper function instead,2093 // but meh this is fine for now.2094 return lane * 1000 + root.interactionThreadID;2095 }2096 function markSpawnedWork(lane) {2097 if (spawnedWorkDuringRender === null) {2098 spawnedWorkDuringRender = [lane];2099 } else {2100 spawnedWorkDuringRender.push(lane);2101 }2102 }2103 function scheduleInteractions(root, lane, interactions) {2104 if (interactions.size > 0) {2105 var pendingInteractionMap = root.pendingInteractionMap;2106 var pendingInteractions = pendingInteractionMap.get(lane);2107 if (pendingInteractions != null) {2108 interactions.forEach(function (interaction) {2109 if (!pendingInteractions.has(interaction)) {2110 // Update the pending async work count for previously unscheduled interaction.2111 interaction.__count++;2112 }2113 pendingInteractions.add(interaction);2114 });2115 } else {2116 pendingInteractionMap.set(lane, new Set(interactions)); // Update the pending async work count for the current interactions.2117 interactions.forEach(function (interaction) {2118 interaction.__count++;2119 });2120 }2121 var subscriber = __subscriberRef.current;2122 if (subscriber !== null) {2123 var threadID = computeThreadID(root, lane);2124 subscriber.onWorkScheduled(interactions, threadID);2125 }2126 }2127 }2128 function schedulePendingInteractions(root, lane) {2129 scheduleInteractions(root, lane, __interactionsRef.current);2130 }2131 function startWorkOnPendingInteractions(root, lanes) {2132 // we can accurately attribute time spent working on it, And so that cascading2133 // work triggered during the render phase will be associated with it.2134 var interactions = new Set();2135 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledLane) {2136 if (includesSomeLane(lanes, scheduledLane)) {2137 scheduledInteractions.forEach(function (interaction) {2138 return interactions.add(interaction);2139 });2140 }2141 }); // Store the current set of interactions on the FiberRoot for a few reasons:2142 // We can re-use it in hot functions like performConcurrentWorkOnRoot()2143 // without having to recalculate it. We will also use it in commitWork() to...
4 - commitWork.js
Source:4 - commitWork.js
...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) {...
commitRootImpl.js
Source:commitRootImpl.js
...187 if (spawnedWorkDuringRender !== null) {188 var expirationTimes = spawnedWorkDuringRender;189 spawnedWorkDuringRender = null;190 for (var i = 0; i < expirationTimes.length; i++) {191 scheduleInteractions(root, expirationTimes[i], root.memoizedInteractions);192 }193 }194 schedulePendingInteractions(root, remainingExpirationTime);195 }196 } else {197 // If there's no remaining work, we can clear the set of already failed198 // error boundaries.199 legacyErrorBoundariesThatAlreadyFailed = null;200 }201 if (enableSchedulerTracing) {202 if (!rootDidHavePassiveEffects) {203 // If there are no passive effects, then we can complete the pending interactions.204 // Otherwise, we'll wait until after the passive effects are flushed.205 // Wait to do this until after remaining work has been scheduled,...
Using AI Code Generation
1const playwright = require('playwright');2const { scheduleInteractions } = require('playwright/lib/internal/inspectorInstrumentation');3(async () => {4 const browser = await playwright.chromium.launch({ headless: false });5 const context = await browser.newContext();6 const page = await context.newPage();7 await scheduleInteractions(page, async (interactions) => {8 await interactions.click('text=Get started');9 await interactions.click('text=Docs');10 await interactions.click('text=API');11 });12 await browser.close();13})();14module.exports = {15 {16 use: {17 viewport: { width: 1920, height: 1080 },18 },19 },20};21const playwright = require('playwright');22const { scheduleInteractions } = require('playwright/lib/internal/inspectorInstrumentation');23test.describe('Playwright', () => {24 test('Playwright', async ({ page }) => {25 await scheduleInteractions(page, async (interactions) => {26 await interactions.click('text=Get started');27 await interactions.click('text=Docs');28 await interactions.click('text=API');29 });30 });31});32module.exports = {33 {34 use: {35 viewport: { width: 1920, height: 1080 },
Using AI Code Generation
1const { scheduleInteractions } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 await scheduleInteractions(page, [7 {8 selector: '#tsf > div:nth-child(2) > div > div.FPdoLc.VlcLAe > center > input[type="submit"]:nth-child(1)',9 position: { x: 0, y: 0 },10 },11 ]);12 await page.screenshot({ path: `example.png` });13 await browser.close();14})();
Using AI Code Generation
1const playwright = require('playwright');2const { scheduleInteractions } = require('playwright/lib/internal/inspector/adapters/inspectorAdapter');3(async () => {4 const browser = await playwright.chromium.launch({ headless: false });5 const page = await browser.newPage();6 await page.waitForSelector('input[name="q"]');7 await scheduleInteractions(page, [8 {9 options: {10 },11 },12 ]);13 await page.screenshot({ path: 'example.png' });14 await browser.close();15})();16module.exports = {17 use: {18 },19};
Using AI Code Generation
1const { scheduleInteractions } = require('playwright/lib/utils/interaction');2const { firefox } = require('playwright');3const run = async () => {4 const browser = await firefox.launch();5 const page = await browser.newPage();6 await scheduleInteractions(page, async (interactions) => {7 await interactions.click(page.locator('input[type="submit"]'));8 });9 await browser.close();10};11run();12 const { page, context } = await state.browser._defaultContextOrPage();13 at scheduleInteractions (node_modules/playwright/lib/utils/interaction.js:14:45)14 at run (test.js:13:5)15 at processTicksAndRejections (internal/process/task_queues.js:97:5)16const { scheduleInteractions } = require('playwright-core/lib/utils/interaction');
Using AI Code Generation
1const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');2const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');3const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');4const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');5const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');6const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');7const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');8const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');9const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');10const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');11const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');12const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');13const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');14const { scheduleInteractions, scheduleInteraction } = require('@playwright/test');15const { scheduleInteractions, scheduleInteraction } = require('@playwright/test/lib/workerRunner');16const { scheduleInteractions, scheduleInteraction } = require('@playwright/test
Using AI Code Generation
1const { scheduleInteractions } = require('playwright');2const { chromium } = require('playwright');3const { Interaction, Interactions } = require('playwright-interactions');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 await scheduleInteractions(page, () => {9 return new Interactions(page)10 .click(page.locator('text=Example Domain'))11 .click(page.locator('text=More information...'))12 .click(page.locator('text=More information...'))13 .click(page.locator('text=More information...'))14 });15 await browser.close();16})();17const { chromium } = require('playwright');18const { Interaction, Interactions } = require('playwright-interactions');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext();22 const page = await context.newPage();23 await new Interactions(page)24 .click(page.locator('text=Example Domain'))25 .click(page.locator('text=More information...'))26 .click(page.locator('text=More information...'))27 .click(page.locator('text=More information...'))28 await browser.close();29})();30const { chromium } = require('playwright');31const { Interaction, Interactions } = require('playwright-interactions');
Using AI Code Generation
1import { scheduleInteractions } from 'playwright/lib/internal';2scheduleInteractions(async () => {3});4import { scheduleInteractions } from 'playwright/lib/internal';5scheduleInteractions(async () => {6});7import { scheduleInteractions } from 'playwright/lib/internal';8scheduleInteractions(async () => {9});10import { scheduleInteractions } from 'playwright/lib/internal';11scheduleInteractions(async () => {12});13import { scheduleInteractions } from 'playwright/lib/internal';14scheduleInteractions(async () => {15});16import { scheduleInteractions } from 'playwright/lib/internal';17scheduleInteractions(async () => {18});19import { scheduleInteractions } from 'playwright/lib/internal';20scheduleInteractions(async () => {21});22import { scheduleInteractions } from 'playwright/lib/internal';23scheduleInteractions(async () => {24});25import { scheduleInteractions } from 'playwright/lib/internal';26scheduleInteractions(async () => {
Using AI Code Generation
1const playwright = require('playwright');2const pw = new playwright();3const browser = pw.chromium;4const page = browser.newPage();5page.scheduleInteractions([6 { action: 'click', selector: '#foo' },7 { action: 'click', selector: '#bar' },8 { action: 'click', selector: '#baz' }9]);10page.runScheduledInteractions();11if(page.scheduledInteractionsCompleted()) {12 console.log('All interactions have been completed');13} else {14 console.log('Not all interactions have been completed');15}16page2.scheduleInteractions([17 { action: 'click', selector: '#foo' },18 { action: 'click', selector: '#bar' },19 { action: 'click', selector: '#baz' }20]);21page2.runScheduledInteractions();22if(page2.scheduledInteractionsCompleted()) {23 console.log('All interactions have been completed');24} else {25 console.log('Not all interactions have been completed');26}27page.scheduleInteractions([28 { action: 'click', selector: '#foo' },29 { action: 'click', selector: '#bar' },30 { action: 'click', selector: '#baz' }31]);32page.runScheduledInteractions();33if(page.scheduledInteractionsCompleted()) {34 console.log('All interactions have been completed');35} else {36 console.log('Not all interactions have been completed');37}
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!