How to use resetChildExpirationTime method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberScheduler.new.js

Source:ReactFiberScheduler.new.js Github

copy

Full Screen

...924 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);925 }926 stopWorkTimer(workInProgress);927 resetCurrentDebugFiberInDEV();928 resetChildExpirationTime(workInProgress);929 if (next !== null) {930 // Completing this fiber spawned new work. Work on that next.931 return next;932 }933 if (934 returnFiber !== null &&935 // Do not append effects to parents if a sibling failed to complete936 (returnFiber.effectTag & Incomplete) === NoEffect937 ) {938 // Append all the effects of the subtree and this fiber onto the effect939 // list of the parent. The completion order of the children affects the940 // side-effect order.941 if (returnFiber.firstEffect === null) {942 returnFiber.firstEffect = workInProgress.firstEffect;943 }944 if (workInProgress.lastEffect !== null) {945 if (returnFiber.lastEffect !== null) {946 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;947 }948 returnFiber.lastEffect = workInProgress.lastEffect;949 }950 // If this fiber had side-effects, we append it AFTER the children's951 // side-effects. We can perform certain side-effects earlier if needed,952 // by doing multiple passes over the effect list. We don't want to953 // schedule our own side-effect on our own list because if end up954 // reusing children we'll schedule this effect onto itself since we're955 // at the end.956 const effectTag = workInProgress.effectTag;957 // Skip both NoWork and PerformedWork tags when creating the effect958 // list. PerformedWork effect is read by React DevTools but shouldn't be959 // committed.960 if (effectTag > PerformedWork) {961 if (returnFiber.lastEffect !== null) {962 returnFiber.lastEffect.nextEffect = workInProgress;963 } else {964 returnFiber.firstEffect = workInProgress;965 }966 returnFiber.lastEffect = workInProgress;967 }968 }969 } else {970 // This fiber did not complete because something threw. Pop values off971 // the stack without entering the complete phase. If this is a boundary,972 // capture values if possible.973 const next = unwindWork(workInProgress, renderExpirationTime);974 // Because this fiber did not complete, don't reset its expiration time.975 if (976 enableProfilerTimer &&977 (workInProgress.mode & ProfileMode) !== NoContext978 ) {979 // Record the render duration for the fiber that errored.980 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);981 // Include the time spent working on failed children before continuing.982 let actualDuration = workInProgress.actualDuration;983 let child = workInProgress.child;984 while (child !== null) {985 actualDuration += child.actualDuration;986 child = child.sibling;987 }988 workInProgress.actualDuration = actualDuration;989 }990 if (next !== null) {991 // If completing this work spawned new work, do that next. We'll come992 // back here again.993 // Since we're restarting, remove anything that is not a host effect994 // from the effect tag.995 // TODO: The name stopFailedWorkTimer is misleading because Suspense996 // also captures and restarts.997 stopFailedWorkTimer(workInProgress);998 next.effectTag &= HostEffectMask;999 return next;1000 }1001 stopWorkTimer(workInProgress);1002 if (returnFiber !== null) {1003 // Mark the parent fiber as incomplete and clear its effect list.1004 returnFiber.firstEffect = returnFiber.lastEffect = null;1005 returnFiber.effectTag |= Incomplete;1006 }1007 }1008 const siblingFiber = workInProgress.sibling;1009 if (siblingFiber !== null) {1010 // If there is more work to do in this returnFiber, do that next.1011 return siblingFiber;1012 }1013 // Otherwise, return to the parent1014 workInProgress = returnFiber;1015 } while (workInProgress !== null);1016 // We've reached the root.1017 if (workInProgressRootExitStatus === RootIncomplete) {1018 workInProgressRootExitStatus = RootCompleted;1019 }1020 return null;1021}1022function resetChildExpirationTime(completedWork: Fiber) {1023 if (1024 renderExpirationTime !== Never &&1025 completedWork.childExpirationTime === Never1026 ) {1027 // The children of this component are hidden. Don't bubble their1028 // expiration times.1029 return;1030 }1031 let newChildExpirationTime = NoWork;1032 // Bubble up the earliest expiration time.1033 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoContext) {1034 // In profiling mode, resetChildExpirationTime is also used to reset1035 // profiler durations.1036 let actualDuration = completedWork.actualDuration;...

Full Screen

Full Screen

ReactFiberCompleteWork.new.js

Source:ReactFiberCompleteWork.new.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {Fiber} from './ReactInternalTypes';10import type {Lanes, Lane} from './ReactFiberLane';11import type {12 ReactFundamentalComponentInstance,13 ReactScopeInstance,14} from 'shared/ReactTypes';15import type {FiberRoot} from './ReactInternalTypes';16import type {17 Instance,18 Type,19 Props,20 Container,21 ChildSet,22} from './ReactFiberHostConfig';23import type {24 SuspenseState,25 SuspenseListRenderState,26} from './ReactFiberSuspenseComponent.new';27import type {SuspenseContext} from './ReactFiberSuspenseContext.new';28import type {OffscreenState} from './ReactFiberOffscreenComponent';29import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.new';30import {now} from './SchedulerWithReactIntegration.new';31import {32 IndeterminateComponent,33 FunctionComponent,34 ClassComponent,35 HostRoot,36 HostComponent,37 HostText,38 HostPortal,39 ContextProvider,40 ContextConsumer,41 ForwardRef,42 Fragment,43 Mode,44 Profiler,45 SuspenseComponent,46 SuspenseListComponent,47 MemoComponent,48 SimpleMemoComponent,49 LazyComponent,50 IncompleteClassComponent,51 FundamentalComponent,52 ScopeComponent,53 Block,54 OffscreenComponent,55 LegacyHiddenComponent,56} from './ReactWorkTags';57import {58 NoMode,59 BlockingMode,60 ConcurrentMode,61 ProfileMode,62} from './ReactTypeOfMode';63import {64 Ref,65 Update,66 Callback,67 Passive,68 Deletion,69 NoFlags,70 DidCapture,71 Snapshot,72 MutationMask,73 LayoutMask,74 PassiveMask,75 StaticMask,76 PerformedWork,77} from './ReactFiberFlags';78import invariant from 'shared/invariant';79import {80 createInstance,81 createTextInstance,82 appendInitialChild,83 finalizeInitialChildren,84 prepareUpdate,85 supportsMutation,86 supportsPersistence,87 cloneInstance,88 cloneHiddenInstance,89 cloneHiddenTextInstance,90 createContainerChildSet,91 appendChildToContainerChildSet,92 finalizeContainerChildren,93 getFundamentalComponentInstance,94 mountFundamentalComponent,95 cloneFundamentalInstance,96 shouldUpdateFundamentalComponent,97 preparePortalMount,98 prepareScopeUpdate,99} from './ReactFiberHostConfig';100import {101 getRootHostContainer,102 popHostContext,103 getHostContext,104 popHostContainer,105} from './ReactFiberHostContext.new';106import {107 suspenseStackCursor,108 InvisibleParentSuspenseContext,109 hasSuspenseContext,110 popSuspenseContext,111 pushSuspenseContext,112 setShallowSuspenseContext,113 ForceSuspenseFallback,114 setDefaultShallowSuspenseContext,115} from './ReactFiberSuspenseContext.new';116import {findFirstSuspended} from './ReactFiberSuspenseComponent.new';117import {118 isContextProvider as isLegacyContextProvider,119 popContext as popLegacyContext,120 popTopLevelContextObject as popTopLevelLegacyContextObject,121} from './ReactFiberContext.new';122import {popProvider} from './ReactFiberNewContext.new';123import {124 prepareToHydrateHostInstance,125 prepareToHydrateHostTextInstance,126 prepareToHydrateHostSuspenseInstance,127 popHydrationState,128 resetHydrationState,129 getIsHydrating,130} from './ReactFiberHydrationContext.new';131import {132 enableSchedulerTracing,133 enableSuspenseCallback,134 enableSuspenseServerRenderer,135 enableFundamentalAPI,136 enableScopeAPI,137 enableBlocksAPI,138 enableProfilerTimer,139} from 'shared/ReactFeatureFlags';140import {141 markSpawnedWork,142 renderDidSuspend,143 renderDidSuspendDelayIfPossible,144 renderHasNotSuspendedYet,145 popRenderLanes,146 getRenderTargetTime,147 subtreeRenderLanes,148} from './ReactFiberWorkLoop.new';149import {createFundamentalStateInstance} from './ReactFiberFundamental.new';150import {151 OffscreenLane,152 SomeRetryLane,153 NoLanes,154 includesSomeLane,155 mergeLanes,156} from './ReactFiberLane';157import {resetChildFibers} from './ReactChildFiber.new';158import {createScopeInstance} from './ReactFiberScope.new';159import {transferActualDuration} from './ReactProfilerTimer.new';160function markUpdate(workInProgress: Fiber) {161 // Tag the fiber with an update effect. This turns a Placement into162 // a PlacementAndUpdate.163 workInProgress.flags |= Update;164}165function markRef(workInProgress: Fiber) {166 workInProgress.flags |= Ref;167}168function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {169 const didBailout = current !== null && current.child === completedWork.child;170 if (didBailout) {171 return true;172 }173 let child = completedWork.child;174 while (child !== null) {175 if ((child.flags & MutationMask) !== NoFlags) {176 return false;177 }178 if ((child.subtreeFlags & MutationMask) !== NoFlags) {179 return false;180 }181 child = child.sibling;182 }183 return true;184}185let appendAllChildren;186let updateHostContainer;187let updateHostComponent;188let updateHostText;189if (supportsMutation) {190 // Mutation mode191 appendAllChildren = function(192 parent: Instance,193 workInProgress: Fiber,194 needsVisibilityToggle: boolean,195 isHidden: boolean,196 ) {197 // We only have the top Fiber that was created but we need recurse down its198 // children to find all the terminal nodes.199 let node = workInProgress.child;200 while (node !== null) {201 if (node.tag === HostComponent || node.tag === HostText) {202 appendInitialChild(parent, node.stateNode);203 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {204 appendInitialChild(parent, node.stateNode.instance);205 } else if (node.tag === HostPortal) {206 // If we have a portal child, then we don't want to traverse207 // down its children. Instead, we'll get insertions from each child in208 // the portal directly.209 } else if (node.child !== null) {210 node.child.return = node;211 node = node.child;212 continue;213 }214 if (node === workInProgress) {215 return;216 }217 while (node.sibling === null) {218 if (node.return === null || node.return === workInProgress) {219 return;220 }221 node = node.return;222 }223 node.sibling.return = node.return;224 node = node.sibling;225 }226 };227 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {228 // Noop229 };230 updateHostComponent = function(231 current: Fiber,232 workInProgress: Fiber,233 type: Type,234 newProps: Props,235 rootContainerInstance: Container,236 ) {237 // If we have an alternate, that means this is an update and we need to238 // schedule a side-effect to do the updates.239 const oldProps = current.memoizedProps;240 if (oldProps === newProps) {241 // In mutation mode, this is sufficient for a bailout because242 // we won't touch this node even if children changed.243 return;244 }245 // If we get updated because one of our children updated, we don't246 // have newProps so we'll have to reuse them.247 // TODO: Split the update API as separate for the props vs. children.248 // Even better would be if children weren't special cased at all tho.249 const instance: Instance = workInProgress.stateNode;250 const currentHostContext = getHostContext();251 // TODO: Experiencing an error where oldProps is null. Suggests a host252 // component is hitting the resume path. Figure out why. Possibly253 // related to `hidden`.254 const updatePayload = prepareUpdate(255 instance,256 type,257 oldProps,258 newProps,259 rootContainerInstance,260 currentHostContext,261 );262 // TODO: Type this specific to this type of component.263 workInProgress.updateQueue = (updatePayload: any);264 // If the update payload indicates that there is a change or if there265 // is a new ref we mark this as an update. All the work is done in commitWork.266 if (updatePayload) {267 markUpdate(workInProgress);268 }269 };270 updateHostText = function(271 current: Fiber,272 workInProgress: Fiber,273 oldText: string,274 newText: string,275 ) {276 // If the text differs, mark it as an update. All the work in done in commitWork.277 if (oldText !== newText) {278 markUpdate(workInProgress);279 }280 };281} else if (supportsPersistence) {282 // Persistent host tree mode283 appendAllChildren = function(284 parent: Instance,285 workInProgress: Fiber,286 needsVisibilityToggle: boolean,287 isHidden: boolean,288 ) {289 // We only have the top Fiber that was created but we need recurse down its290 // children to find all the terminal nodes.291 let node = workInProgress.child;292 while (node !== null) {293 // eslint-disable-next-line no-labels294 branches: if (node.tag === HostComponent) {295 let instance = node.stateNode;296 if (needsVisibilityToggle && isHidden) {297 // This child is inside a timed out tree. Hide it.298 const props = node.memoizedProps;299 const type = node.type;300 instance = cloneHiddenInstance(instance, type, props, node);301 }302 appendInitialChild(parent, instance);303 } else if (node.tag === HostText) {304 let instance = node.stateNode;305 if (needsVisibilityToggle && isHidden) {306 // This child is inside a timed out tree. Hide it.307 const text = node.memoizedProps;308 instance = cloneHiddenTextInstance(instance, text, node);309 }310 appendInitialChild(parent, instance);311 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {312 let instance = node.stateNode.instance;313 if (needsVisibilityToggle && isHidden) {314 // This child is inside a timed out tree. Hide it.315 const props = node.memoizedProps;316 const type = node.type;317 instance = cloneHiddenInstance(instance, type, props, node);318 }319 appendInitialChild(parent, instance);320 } else if (node.tag === HostPortal) {321 // If we have a portal child, then we don't want to traverse322 // down its children. Instead, we'll get insertions from each child in323 // the portal directly.324 } else if (node.tag === SuspenseComponent) {325 if ((node.flags & Update) !== NoFlags) {326 // Need to toggle the visibility of the primary children.327 const newIsHidden = node.memoizedState !== null;328 if (newIsHidden) {329 const primaryChildParent = node.child;330 if (primaryChildParent !== null) {331 if (primaryChildParent.child !== null) {332 primaryChildParent.child.return = primaryChildParent;333 appendAllChildren(334 parent,335 primaryChildParent,336 true,337 newIsHidden,338 );339 }340 const fallbackChildParent = primaryChildParent.sibling;341 if (fallbackChildParent !== null) {342 fallbackChildParent.return = node;343 node = fallbackChildParent;344 continue;345 }346 }347 }348 }349 if (node.child !== null) {350 // Continue traversing like normal351 node.child.return = node;352 node = node.child;353 continue;354 }355 } else if (node.child !== null) {356 node.child.return = node;357 node = node.child;358 continue;359 }360 // $FlowFixMe This is correct but Flow is confused by the labeled break.361 node = (node: Fiber);362 if (node === workInProgress) {363 return;364 }365 while (node.sibling === null) {366 if (node.return === null || node.return === workInProgress) {367 return;368 }369 node = node.return;370 }371 node.sibling.return = node.return;372 node = node.sibling;373 }374 };375 // An unfortunate fork of appendAllChildren because we have two different parent types.376 const appendAllChildrenToContainer = function(377 containerChildSet: ChildSet,378 workInProgress: Fiber,379 needsVisibilityToggle: boolean,380 isHidden: boolean,381 ) {382 // We only have the top Fiber that was created but we need recurse down its383 // children to find all the terminal nodes.384 let node = workInProgress.child;385 while (node !== null) {386 // eslint-disable-next-line no-labels387 branches: if (node.tag === HostComponent) {388 let instance = node.stateNode;389 if (needsVisibilityToggle && isHidden) {390 // This child is inside a timed out tree. Hide it.391 const props = node.memoizedProps;392 const type = node.type;393 instance = cloneHiddenInstance(instance, type, props, node);394 }395 appendChildToContainerChildSet(containerChildSet, instance);396 } else if (node.tag === HostText) {397 let instance = node.stateNode;398 if (needsVisibilityToggle && isHidden) {399 // This child is inside a timed out tree. Hide it.400 const text = node.memoizedProps;401 instance = cloneHiddenTextInstance(instance, text, node);402 }403 appendChildToContainerChildSet(containerChildSet, instance);404 } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {405 let instance = node.stateNode.instance;406 if (needsVisibilityToggle && isHidden) {407 // This child is inside a timed out tree. Hide it.408 const props = node.memoizedProps;409 const type = node.type;410 instance = cloneHiddenInstance(instance, type, props, node);411 }412 appendChildToContainerChildSet(containerChildSet, instance);413 } else if (node.tag === HostPortal) {414 // If we have a portal child, then we don't want to traverse415 // down its children. Instead, we'll get insertions from each child in416 // the portal directly.417 } else if (node.tag === SuspenseComponent) {418 if ((node.flags & Update) !== NoFlags) {419 // Need to toggle the visibility of the primary children.420 const newIsHidden = node.memoizedState !== null;421 if (newIsHidden) {422 const primaryChildParent = node.child;423 if (primaryChildParent !== null) {424 if (primaryChildParent.child !== null) {425 primaryChildParent.child.return = primaryChildParent;426 appendAllChildrenToContainer(427 containerChildSet,428 primaryChildParent,429 true,430 newIsHidden,431 );432 }433 const fallbackChildParent = primaryChildParent.sibling;434 if (fallbackChildParent !== null) {435 fallbackChildParent.return = node;436 node = fallbackChildParent;437 continue;438 }439 }440 }441 }442 if (node.child !== null) {443 // Continue traversing like normal444 node.child.return = node;445 node = node.child;446 continue;447 }448 } else if (node.child !== null) {449 node.child.return = node;450 node = node.child;451 continue;452 }453 // $FlowFixMe This is correct but Flow is confused by the labeled break.454 node = (node: Fiber);455 if (node === workInProgress) {456 return;457 }458 while (node.sibling === null) {459 if (node.return === null || node.return === workInProgress) {460 return;461 }462 node = node.return;463 }464 node.sibling.return = node.return;465 node = node.sibling;466 }467 };468 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {469 const portalOrRoot: {470 containerInfo: Container,471 pendingChildren: ChildSet,472 ...473 } = workInProgress.stateNode;474 const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);475 if (childrenUnchanged) {476 // No changes, just reuse the existing instance.477 } else {478 const container = portalOrRoot.containerInfo;479 const newChildSet = createContainerChildSet(container);480 // If children might have changed, we have to add them all to the set.481 appendAllChildrenToContainer(newChildSet, workInProgress, false, false);482 portalOrRoot.pendingChildren = newChildSet;483 // Schedule an update on the container to swap out the container.484 markUpdate(workInProgress);485 finalizeContainerChildren(container, newChildSet);486 }487 };488 updateHostComponent = function(489 current: Fiber,490 workInProgress: Fiber,491 type: Type,492 newProps: Props,493 rootContainerInstance: Container,494 ) {495 const currentInstance = current.stateNode;496 const oldProps = current.memoizedProps;497 // If there are no effects associated with this node, then none of our children had any updates.498 // This guarantees that we can reuse all of them.499 const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);500 if (childrenUnchanged && oldProps === newProps) {501 // No changes, just reuse the existing instance.502 // Note that this might release a previous clone.503 workInProgress.stateNode = currentInstance;504 return;505 }506 const recyclableInstance: Instance = workInProgress.stateNode;507 const currentHostContext = getHostContext();508 let updatePayload = null;509 if (oldProps !== newProps) {510 updatePayload = prepareUpdate(511 recyclableInstance,512 type,513 oldProps,514 newProps,515 rootContainerInstance,516 currentHostContext,517 );518 }519 if (childrenUnchanged && updatePayload === null) {520 // No changes, just reuse the existing instance.521 // Note that this might release a previous clone.522 workInProgress.stateNode = currentInstance;523 return;524 }525 const newInstance = cloneInstance(526 currentInstance,527 updatePayload,528 type,529 oldProps,530 newProps,531 workInProgress,532 childrenUnchanged,533 recyclableInstance,534 );535 if (536 finalizeInitialChildren(537 newInstance,538 type,539 newProps,540 rootContainerInstance,541 currentHostContext,542 )543 ) {544 markUpdate(workInProgress);545 }546 workInProgress.stateNode = newInstance;547 if (childrenUnchanged) {548 // If there are no other effects in this tree, we need to flag this node as having one.549 // Even though we're not going to use it for anything.550 // Otherwise parents won't know that there are new children to propagate upwards.551 markUpdate(workInProgress);552 } else {553 // If children might have changed, we have to add them all to the set.554 appendAllChildren(newInstance, workInProgress, false, false);555 }556 };557 updateHostText = function(558 current: Fiber,559 workInProgress: Fiber,560 oldText: string,561 newText: string,562 ) {563 if (oldText !== newText) {564 // If the text content differs, we'll create a new text instance for it.565 const rootContainerInstance = getRootHostContainer();566 const currentHostContext = getHostContext();567 workInProgress.stateNode = createTextInstance(568 newText,569 rootContainerInstance,570 currentHostContext,571 workInProgress,572 );573 // We'll have to mark it as having an effect, even though we won't use the effect for anything.574 // This lets the parents know that at least one of their children has changed.575 markUpdate(workInProgress);576 } else {577 workInProgress.stateNode = current.stateNode;578 }579 };580} else {581 // No host operations582 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {583 // Noop584 };585 updateHostComponent = function(586 current: Fiber,587 workInProgress: Fiber,588 type: Type,589 newProps: Props,590 rootContainerInstance: Container,591 ) {592 // Noop593 };594 updateHostText = function(595 current: Fiber,596 workInProgress: Fiber,597 oldText: string,598 newText: string,599 ) {600 // Noop601 };602}603function cutOffTailIfNeeded(604 renderState: SuspenseListRenderState,605 hasRenderedATailFallback: boolean,606) {607 if (getIsHydrating()) {608 // If we're hydrating, we should consume as many items as we can609 // so we don't leave any behind.610 return;611 }612 switch (renderState.tailMode) {613 case 'hidden': {614 // Any insertions at the end of the tail list after this point615 // should be invisible. If there are already mounted boundaries616 // anything before them are not considered for collapsing.617 // Therefore we need to go through the whole tail to find if618 // there are any.619 let tailNode = renderState.tail;620 let lastTailNode = null;621 while (tailNode !== null) {622 if (tailNode.alternate !== null) {623 lastTailNode = tailNode;624 }625 tailNode = tailNode.sibling;626 }627 // Next we're simply going to delete all insertions after the628 // last rendered item.629 if (lastTailNode === null) {630 // All remaining items in the tail are insertions.631 renderState.tail = null;632 } else {633 // Detach the insertion after the last node that was already634 // inserted.635 lastTailNode.sibling = null;636 }637 break;638 }639 case 'collapsed': {640 // Any insertions at the end of the tail list after this point641 // should be invisible. If there are already mounted boundaries642 // anything before them are not considered for collapsing.643 // Therefore we need to go through the whole tail to find if644 // there are any.645 let tailNode = renderState.tail;646 let lastTailNode = null;647 while (tailNode !== null) {648 if (tailNode.alternate !== null) {649 lastTailNode = tailNode;650 }651 tailNode = tailNode.sibling;652 }653 // Next we're simply going to delete all insertions after the654 // last rendered item.655 if (lastTailNode === null) {656 // All remaining items in the tail are insertions.657 if (!hasRenderedATailFallback && renderState.tail !== null) {658 // We suspended during the head. We want to show at least one659 // row at the tail. So we'll keep on and cut off the rest.660 renderState.tail.sibling = null;661 } else {662 renderState.tail = null;663 }664 } else {665 // Detach the insertion after the last node that was already666 // inserted.667 lastTailNode.sibling = null;668 }669 break;670 }671 }672}673function bubbleProperties(completedWork: Fiber) {674 const didBailout =675 completedWork.alternate !== null &&676 completedWork.alternate.child === completedWork.child;677 let newChildLanes = NoLanes;678 let subtreeFlags = NoFlags;679 if (!didBailout) {680 // Bubble up the earliest expiration time.681 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {682 // In profiling mode, resetChildExpirationTime is also used to reset683 // profiler durations.684 let actualDuration = completedWork.actualDuration;685 let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);686 let child = completedWork.child;687 while (child !== null) {688 newChildLanes = mergeLanes(689 newChildLanes,690 mergeLanes(child.lanes, child.childLanes),691 );692 subtreeFlags |= child.subtreeFlags;693 subtreeFlags |= child.flags;694 // When a fiber is cloned, its actualDuration is reset to 0. This value will695 // only be updated if work is done on the fiber (i.e. it doesn't bailout).696 // When work is done, it should bubble to the parent's actualDuration. If697 // the fiber has not been cloned though, (meaning no work was done), then698 // this value will reflect the amount of time spent working on a previous699 // render. In that case it should not bubble. We determine whether it was700 // cloned by comparing the child pointer.701 actualDuration += child.actualDuration;702 treeBaseDuration += child.treeBaseDuration;703 child = child.sibling;704 }705 completedWork.actualDuration = actualDuration;706 completedWork.treeBaseDuration = treeBaseDuration;707 } else {708 let child = completedWork.child;709 while (child !== null) {710 newChildLanes = mergeLanes(711 newChildLanes,712 mergeLanes(child.lanes, child.childLanes),713 );714 subtreeFlags |= child.subtreeFlags;715 subtreeFlags |= child.flags;716 child = child.sibling;717 }718 }719 completedWork.subtreeFlags |= subtreeFlags;720 } else {721 // Bubble up the earliest expiration time.722 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {723 // In profiling mode, resetChildExpirationTime is also used to reset724 // profiler durations.725 let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);726 let child = completedWork.child;727 while (child !== null) {728 newChildLanes = mergeLanes(729 newChildLanes,730 mergeLanes(child.lanes, child.childLanes),731 );732 // "Static" flags share the lifetime of the fiber/hook they belong to,733 // so we should bubble those up even during a bailout. All the other734 // flags have a lifetime only of a single render + commit, so we should735 // ignore them.736 subtreeFlags |= child.subtreeFlags & StaticMask;737 subtreeFlags |= child.flags & StaticMask;738 treeBaseDuration += child.treeBaseDuration;739 child = child.sibling;740 }741 completedWork.treeBaseDuration = treeBaseDuration;742 } else {743 let child = completedWork.child;744 while (child !== null) {745 newChildLanes = mergeLanes(746 newChildLanes,747 mergeLanes(child.lanes, child.childLanes),748 );749 // "Static" flags share the lifetime of the fiber/hook they belong to,750 // so we should bubble those up even during a bailout. All the other751 // flags have a lifetime only of a single render + commit, so we should752 // ignore them.753 subtreeFlags |= child.subtreeFlags & StaticMask;754 subtreeFlags |= child.flags & StaticMask;755 child = child.sibling;756 }757 }758 completedWork.subtreeFlags |= subtreeFlags;759 }760 completedWork.childLanes = newChildLanes;761 return didBailout;762}763function completeWork(764 current: Fiber | null,765 workInProgress: Fiber,766 renderLanes: Lanes,767): Fiber | null {768 const newProps = workInProgress.pendingProps;769 switch (workInProgress.tag) {770 case IndeterminateComponent:771 case LazyComponent:772 case SimpleMemoComponent:773 case FunctionComponent:774 case ForwardRef:775 case Fragment:776 case Mode:777 case ContextConsumer:778 case MemoComponent:779 bubbleProperties(workInProgress);780 return null;781 case ClassComponent: {782 const Component = workInProgress.type;783 if (isLegacyContextProvider(Component)) {784 popLegacyContext(workInProgress);785 }786 bubbleProperties(workInProgress);787 return null;788 }789 case HostRoot: {790 popHostContainer(workInProgress);791 popTopLevelLegacyContextObject(workInProgress);792 resetMutableSourceWorkInProgressVersions();793 const fiberRoot = (workInProgress.stateNode: FiberRoot);794 if (fiberRoot.pendingContext) {795 fiberRoot.context = fiberRoot.pendingContext;796 fiberRoot.pendingContext = null;797 }798 if (current === null || current.child === null) {799 // If we hydrated, pop so that we can delete any remaining children800 // that weren't hydrated.801 const wasHydrated = popHydrationState(workInProgress);802 if (wasHydrated) {803 // If we hydrated, then we'll need to schedule an update for804 // the commit side-effects on the root.805 markUpdate(workInProgress);806 } else if (!fiberRoot.hydrate) {807 // Schedule an effect to clear this container at the start of the next commit.808 // This handles the case of React rendering into a container with previous children.809 // It's also safe to do for updates too, because current.child would only be null810 // if the previous render was null (so the the container would already be empty).811 workInProgress.flags |= Snapshot;812 }813 }814 updateHostContainer(current, workInProgress);815 bubbleProperties(workInProgress);816 return null;817 }818 case HostComponent: {819 popHostContext(workInProgress);820 const rootContainerInstance = getRootHostContainer();821 const type = workInProgress.type;822 if (current !== null && workInProgress.stateNode != null) {823 updateHostComponent(824 current,825 workInProgress,826 type,827 newProps,828 rootContainerInstance,829 );830 if (current.ref !== workInProgress.ref) {831 markRef(workInProgress);832 }833 } else {834 if (!newProps) {835 invariant(836 workInProgress.stateNode !== null,837 'We must have new props for new mounts. This error is likely ' +838 'caused by a bug in React. Please file an issue.',839 );840 // This can happen when we abort work.841 bubbleProperties(workInProgress);842 return null;843 }844 const currentHostContext = getHostContext();845 // TODO: Move createInstance to beginWork and keep it on a context846 // "stack" as the parent. Then append children as we go in beginWork847 // or completeWork depending on whether we want to add them top->down or848 // bottom->up. Top->down is faster in IE11.849 const wasHydrated = popHydrationState(workInProgress);850 if (wasHydrated) {851 // TODO: Move this and createInstance step into the beginPhase852 // to consolidate.853 if (854 prepareToHydrateHostInstance(855 workInProgress,856 rootContainerInstance,857 currentHostContext,858 )859 ) {860 // If changes to the hydrated node need to be applied at the861 // commit-phase we mark this as such.862 markUpdate(workInProgress);863 }864 } else {865 const instance = createInstance(866 type,867 newProps,868 rootContainerInstance,869 currentHostContext,870 workInProgress,871 );872 appendAllChildren(instance, workInProgress, false, false);873 workInProgress.stateNode = instance;874 // Certain renderers require commit-time effects for initial mount.875 // (eg DOM renderer supports auto-focus for certain elements).876 // Make sure such renderers get scheduled for later work.877 if (878 finalizeInitialChildren(879 instance,880 type,881 newProps,882 rootContainerInstance,883 currentHostContext,884 )885 ) {886 markUpdate(workInProgress);887 }888 }889 if (workInProgress.ref !== null) {890 // If there is a ref on a host node we need to schedule a callback891 markRef(workInProgress);892 }893 }894 bubbleProperties(workInProgress);895 return null;896 }897 case HostText: {898 const newText = newProps;899 if (current && workInProgress.stateNode != null) {900 const oldText = current.memoizedProps;901 // If we have an alternate, that means this is an update and we need902 // to schedule a side-effect to do the updates.903 updateHostText(current, workInProgress, oldText, newText);904 } else {905 if (typeof newText !== 'string') {906 invariant(907 workInProgress.stateNode !== null,908 'We must have new props for new mounts. This error is likely ' +909 'caused by a bug in React. Please file an issue.',910 );911 // This can happen when we abort work.912 }913 const rootContainerInstance = getRootHostContainer();914 const currentHostContext = getHostContext();915 const wasHydrated = popHydrationState(workInProgress);916 if (wasHydrated) {917 if (prepareToHydrateHostTextInstance(workInProgress)) {918 markUpdate(workInProgress);919 }920 } else {921 workInProgress.stateNode = createTextInstance(922 newText,923 rootContainerInstance,924 currentHostContext,925 workInProgress,926 );927 }928 }929 bubbleProperties(workInProgress);930 return null;931 }932 case Profiler: {933 const didBailout = bubbleProperties(workInProgress);934 if (!didBailout) {935 // Use subtreeFlags to determine which commit callbacks should fire.936 // TODO: Move this logic to the commit phase, since we already check if937 // a fiber's subtree contains effects. Refactor the commit phase's938 // depth-first traversal so that we can put work tag-specific logic939 // before or after committing a subtree's effects.940 const OnRenderFlag = Update;941 const OnCommitFlag = Callback;942 const OnPostCommitFlag = Passive;943 const subtreeFlags = workInProgress.subtreeFlags;944 const flags = workInProgress.flags;945 let newFlags = flags;946 // Call onRender any time this fiber or its subtree are worked on.947 if (948 (flags & PerformedWork) !== NoFlags ||949 (subtreeFlags & PerformedWork) !== NoFlags950 ) {951 newFlags |= OnRenderFlag;952 }953 // Call onCommit only if the subtree contains layout work, or if it954 // contains deletions, since those might result in unmount work, which955 // we include in the same measure.956 // TODO: Can optimize by using a static flag to track whether a tree957 // contains layout effects, like we do for passive effects.958 if (959 (flags & (LayoutMask | Deletion)) !== NoFlags ||960 (subtreeFlags & (LayoutMask | Deletion)) !== NoFlags961 ) {962 newFlags |= OnCommitFlag;963 }964 // Call onPostCommit only if the subtree contains passive work.965 // Don't have to check for deletions, because Deletion is already966 // a passive flag.967 if (968 (flags & PassiveMask) !== NoFlags ||969 (subtreeFlags & PassiveMask) !== NoFlags970 ) {971 newFlags |= OnPostCommitFlag;972 }973 workInProgress.flags = newFlags;974 } else {975 // This fiber and its subtree bailed out, so don't fire any callbacks.976 }977 return null;978 }979 case SuspenseComponent: {980 popSuspenseContext(workInProgress);981 const nextState: null | SuspenseState = workInProgress.memoizedState;982 if (enableSuspenseServerRenderer) {983 if (nextState !== null && nextState.dehydrated !== null) {984 if (current === null) {985 const wasHydrated = popHydrationState(workInProgress);986 invariant(987 wasHydrated,988 'A dehydrated suspense component was completed without a hydrated node. ' +989 'This is probably a bug in React.',990 );991 prepareToHydrateHostSuspenseInstance(workInProgress);992 if (enableSchedulerTracing) {993 markSpawnedWork(OffscreenLane);994 }995 bubbleProperties(workInProgress);996 if (enableProfilerTimer) {997 if ((workInProgress.mode & ProfileMode) !== NoMode) {998 const isTimedOutSuspense = nextState !== null;999 if (isTimedOutSuspense) {1000 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1001 const primaryChildFragment = workInProgress.child;1002 if (primaryChildFragment !== null) {1003 // $FlowFixMe Flow doens't support type casting in combiation with the -= operator1004 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);1005 }1006 }1007 }1008 }1009 return null;1010 } else {1011 // We should never have been in a hydration state if we didn't have a current.1012 // However, in some of those paths, we might have reentered a hydration state1013 // and then we might be inside a hydration state. In that case, we'll need to exit out of it.1014 resetHydrationState();1015 if ((workInProgress.flags & DidCapture) === NoFlags) {1016 // This boundary did not suspend so it's now hydrated and unsuspended.1017 workInProgress.memoizedState = null;1018 }1019 // If nothing suspended, we need to schedule an effect to mark this boundary1020 // as having hydrated so events know that they're free to be invoked.1021 // It's also a signal to replay events and the suspense callback.1022 // If something suspended, schedule an effect to attach retry listeners.1023 // So we might as well always mark this.1024 workInProgress.flags |= Update;1025 bubbleProperties(workInProgress);1026 if (enableProfilerTimer) {1027 if ((workInProgress.mode & ProfileMode) !== NoMode) {1028 const isTimedOutSuspense = nextState !== null;1029 if (isTimedOutSuspense) {1030 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1031 const primaryChildFragment = workInProgress.child;1032 if (primaryChildFragment !== null) {1033 // $FlowFixMe Flow doens't support type casting in combiation with the -= operator1034 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);1035 }1036 }1037 }1038 }1039 return null;1040 }1041 }1042 }1043 if ((workInProgress.flags & DidCapture) !== NoFlags) {1044 // Something suspended. Re-render with the fallback children.1045 workInProgress.lanes = renderLanes;1046 // Do not reset the effect list.1047 if (1048 enableProfilerTimer &&1049 (workInProgress.mode & ProfileMode) !== NoMode1050 ) {1051 transferActualDuration(workInProgress);1052 }1053 // Don't bubble properties in this case.1054 return workInProgress;1055 }1056 const nextDidTimeout = nextState !== null;1057 let prevDidTimeout = false;1058 if (current === null) {1059 if (workInProgress.memoizedProps.fallback !== undefined) {1060 popHydrationState(workInProgress);1061 }1062 } else {1063 const prevState: null | SuspenseState = current.memoizedState;1064 prevDidTimeout = prevState !== null;1065 }1066 if (nextDidTimeout && !prevDidTimeout) {1067 // If this subtreee is running in blocking mode we can suspend,1068 // otherwise we won't suspend.1069 // TODO: This will still suspend a synchronous tree if anything1070 // in the concurrent tree already suspended during this render.1071 // This is a known bug.1072 if ((workInProgress.mode & BlockingMode) !== NoMode) {1073 // TODO: Move this back to throwException because this is too late1074 // if this is a large tree which is common for initial loads. We1075 // don't know if we should restart a render or not until we get1076 // this marker, and this is too late.1077 // If this render already had a ping or lower pri updates,1078 // and this is the first time we know we're going to suspend we1079 // should be able to immediately restart from within throwException.1080 const hasInvisibleChildContext =1081 current === null &&1082 workInProgress.memoizedProps.unstable_avoidThisFallback !== true;1083 if (1084 hasInvisibleChildContext ||1085 hasSuspenseContext(1086 suspenseStackCursor.current,1087 (InvisibleParentSuspenseContext: SuspenseContext),1088 )1089 ) {1090 // If this was in an invisible tree or a new render, then showing1091 // this boundary is ok.1092 renderDidSuspend();1093 } else {1094 // Otherwise, we're going to have to hide content so we should1095 // suspend for longer if possible.1096 renderDidSuspendDelayIfPossible();1097 }1098 }1099 }1100 if (supportsPersistence) {1101 // TODO: Only schedule updates if not prevDidTimeout.1102 if (nextDidTimeout) {1103 // If this boundary just timed out, schedule an effect to attach a1104 // retry listener to the promise. This flag is also used to hide the1105 // primary children.1106 workInProgress.flags |= Update;1107 }1108 }1109 if (supportsMutation) {1110 // TODO: Only schedule updates if these values are non equal, i.e. it changed.1111 if (nextDidTimeout || prevDidTimeout) {1112 // If this boundary just timed out, schedule an effect to attach a1113 // retry listener to the promise. This flag is also used to hide the1114 // primary children. In mutation mode, we also need the flag to1115 // *unhide* children that were previously hidden, so check if this1116 // is currently timed out, too.1117 workInProgress.flags |= Update;1118 }1119 }1120 if (1121 enableSuspenseCallback &&1122 workInProgress.updateQueue !== null &&1123 workInProgress.memoizedProps.suspenseCallback != null1124 ) {1125 // Always notify the callback1126 workInProgress.flags |= Update;1127 }1128 bubbleProperties(workInProgress);1129 if (enableProfilerTimer) {1130 if ((workInProgress.mode & ProfileMode) !== NoMode) {1131 if (nextDidTimeout) {1132 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1133 const primaryChildFragment = workInProgress.child;1134 if (primaryChildFragment !== null) {1135 // $FlowFixMe Flow doens't support type casting in combiation with the -= operator1136 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);1137 }1138 }1139 }1140 }1141 return null;1142 }1143 case HostPortal:1144 popHostContainer(workInProgress);1145 updateHostContainer(current, workInProgress);1146 if (current === null) {1147 preparePortalMount(workInProgress.stateNode.containerInfo);1148 }1149 bubbleProperties(workInProgress);1150 return null;1151 case ContextProvider:1152 // Pop provider fiber1153 popProvider(workInProgress);1154 bubbleProperties(workInProgress);1155 return null;1156 case IncompleteClassComponent: {1157 // Same as class component case. I put it down here so that the tags are1158 // sequential to ensure this switch is compiled to a jump table.1159 const Component = workInProgress.type;1160 if (isLegacyContextProvider(Component)) {1161 popLegacyContext(workInProgress);1162 }1163 bubbleProperties(workInProgress);1164 return null;1165 }1166 case SuspenseListComponent: {1167 popSuspenseContext(workInProgress);1168 const renderState: null | SuspenseListRenderState =1169 workInProgress.memoizedState;1170 if (renderState === null) {1171 // We're running in the default, "independent" mode.1172 // We don't do anything in this mode.1173 bubbleProperties(workInProgress);1174 return null;1175 }1176 let didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags;1177 const renderedTail = renderState.rendering;1178 if (renderedTail === null) {1179 // We just rendered the head.1180 if (!didSuspendAlready) {1181 // This is the first pass. We need to figure out if anything is still1182 // suspended in the rendered set.1183 // If new content unsuspended, but there's still some content that1184 // didn't. Then we need to do a second pass that forces everything1185 // to keep showing their fallbacks.1186 // We might be suspended if something in this render pass suspended, or1187 // something in the previous committed pass suspended. Otherwise,1188 // there's no chance so we can skip the expensive call to1189 // findFirstSuspended.1190 const cannotBeSuspended =1191 renderHasNotSuspendedYet() &&1192 (current === null || (current.flags & DidCapture) === NoFlags);1193 if (!cannotBeSuspended) {1194 let row = workInProgress.child;1195 while (row !== null) {1196 const suspended = findFirstSuspended(row);1197 if (suspended !== null) {1198 didSuspendAlready = true;1199 workInProgress.flags |= DidCapture;1200 cutOffTailIfNeeded(renderState, false);1201 // If this is a newly suspended tree, it might not get committed as1202 // part of the second pass. In that case nothing will subscribe to1203 // its thennables. Instead, we'll transfer its thennables to the1204 // SuspenseList so that it can retry if they resolve.1205 // There might be multiple of these in the list but since we're1206 // going to wait for all of them anyway, it doesn't really matter1207 // which ones gets to ping. In theory we could get clever and keep1208 // track of how many dependencies remain but it gets tricky because1209 // in the meantime, we can add/remove/change items and dependencies.1210 // We might bail out of the loop before finding any but that1211 // doesn't matter since that means that the other boundaries that1212 // we did find already has their listeners attached.1213 const newThennables = suspended.updateQueue;1214 if (newThennables !== null) {1215 workInProgress.updateQueue = newThennables;1216 workInProgress.flags |= Update;1217 }1218 // Rerender the whole list, but this time, we'll force fallbacks1219 // to stay in place.1220 // Reset the child fibers to their original state.1221 workInProgress.subtreeFlags = NoFlags;1222 resetChildFibers(workInProgress, renderLanes);1223 // Set up the Suspense Context to force suspense and immediately1224 // rerender the children.1225 pushSuspenseContext(1226 workInProgress,1227 setShallowSuspenseContext(1228 suspenseStackCursor.current,1229 ForceSuspenseFallback,1230 ),1231 );1232 // Don't bubble properties in this case.1233 return workInProgress.child;1234 }1235 row = row.sibling;1236 }1237 }1238 if (renderState.tail !== null && now() > getRenderTargetTime()) {1239 // We have already passed our CPU deadline but we still have rows1240 // left in the tail. We'll just give up further attempts to render1241 // the main content and only render fallbacks.1242 workInProgress.flags |= DidCapture;1243 didSuspendAlready = true;1244 cutOffTailIfNeeded(renderState, false);1245 // Since nothing actually suspended, there will nothing to ping this1246 // to get it started back up to attempt the next item. While in terms1247 // of priority this work has the same priority as this current render,1248 // it's not part of the same transition once the transition has1249 // committed. If it's sync, we still want to yield so that it can be1250 // painted. Conceptually, this is really the same as pinging.1251 // We can use any RetryLane even if it's the one currently rendering1252 // since we're leaving it behind on this node.1253 workInProgress.lanes = SomeRetryLane;1254 if (enableSchedulerTracing) {1255 markSpawnedWork(SomeRetryLane);1256 }1257 }1258 } else {1259 cutOffTailIfNeeded(renderState, false);1260 }1261 // Next we're going to render the tail.1262 } else {1263 // Append the rendered row to the child list.1264 if (!didSuspendAlready) {1265 const suspended = findFirstSuspended(renderedTail);1266 if (suspended !== null) {1267 workInProgress.flags |= DidCapture;1268 didSuspendAlready = true;1269 // Ensure we transfer the update queue to the parent so that it doesn't1270 // get lost if this row ends up dropped during a second pass.1271 const newThennables = suspended.updateQueue;1272 if (newThennables !== null) {1273 workInProgress.updateQueue = newThennables;1274 workInProgress.flags |= Update;1275 }1276 cutOffTailIfNeeded(renderState, true);1277 // This might have been modified.1278 if (1279 renderState.tail === null &&1280 renderState.tailMode === 'hidden' &&1281 !renderedTail.alternate &&1282 !getIsHydrating() // We don't cut it if we're hydrating.1283 ) {1284 // We're done.1285 bubbleProperties(workInProgress);1286 return null;1287 }1288 } else if (1289 // The time it took to render last row is greater than the remaining1290 // time we have to render. So rendering one more row would likely1291 // exceed it.1292 now() * 2 - renderState.renderingStartTime >1293 getRenderTargetTime() &&1294 renderLanes !== OffscreenLane1295 ) {1296 // We have now passed our CPU deadline and we'll just give up further1297 // attempts to render the main content and only render fallbacks.1298 // The assumption is that this is usually faster.1299 workInProgress.flags |= DidCapture;1300 didSuspendAlready = true;1301 cutOffTailIfNeeded(renderState, false);1302 // Since nothing actually suspended, there will nothing to ping this1303 // to get it started back up to attempt the next item. If we can show1304 // them, then they really have the same priority as this render.1305 // So we'll pick it back up the very next render pass once we've had1306 // an opportunity to yield for paint.1307 workInProgress.lanes = SomeRetryLane;1308 if (enableSchedulerTracing) {1309 markSpawnedWork(SomeRetryLane);1310 }1311 }1312 }1313 if (renderState.isBackwards) {1314 // The effect list of the backwards tail will have been added1315 // to the end. This breaks the guarantee that life-cycles fire in1316 // sibling order but that isn't a strong guarantee promised by React.1317 // Especially since these might also just pop in during future commits.1318 // Append to the beginning of the list.1319 renderedTail.sibling = workInProgress.child;1320 workInProgress.child = renderedTail;1321 } else {1322 const previousSibling = renderState.last;1323 if (previousSibling !== null) {1324 previousSibling.sibling = renderedTail;1325 } else {1326 workInProgress.child = renderedTail;1327 }1328 renderState.last = renderedTail;1329 }1330 }1331 if (renderState.tail !== null) {1332 // We still have tail rows to render.1333 // Pop a row.1334 const next = renderState.tail;1335 renderState.rendering = next;1336 renderState.tail = next.sibling;1337 renderState.renderingStartTime = now();1338 next.sibling = null;1339 // Restore the context.1340 // TODO: We can probably just avoid popping it instead and only1341 // setting it the first time we go from not suspended to suspended.1342 let suspenseContext = suspenseStackCursor.current;1343 if (didSuspendAlready) {1344 suspenseContext = setShallowSuspenseContext(1345 suspenseContext,1346 ForceSuspenseFallback,1347 );1348 } else {1349 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);1350 }1351 pushSuspenseContext(workInProgress, suspenseContext);1352 // Do a pass over the next row.1353 // Don't bubble properties in this case.1354 return next;1355 }1356 bubbleProperties(workInProgress);1357 return null;1358 }1359 case FundamentalComponent: {1360 if (enableFundamentalAPI) {1361 const fundamentalImpl = workInProgress.type.impl;1362 let fundamentalInstance: ReactFundamentalComponentInstance<1363 any,1364 any,1365 > | null = workInProgress.stateNode;1366 if (fundamentalInstance === null) {1367 const getInitialState = fundamentalImpl.getInitialState;1368 let fundamentalState;1369 if (getInitialState !== undefined) {1370 fundamentalState = getInitialState(newProps);1371 }1372 fundamentalInstance = workInProgress.stateNode = createFundamentalStateInstance(1373 workInProgress,1374 newProps,1375 fundamentalImpl,1376 fundamentalState || {},1377 );1378 const instance = ((getFundamentalComponentInstance(1379 fundamentalInstance,1380 ): any): Instance);1381 fundamentalInstance.instance = instance;1382 if (fundamentalImpl.reconcileChildren === false) {1383 bubbleProperties(workInProgress);1384 return null;1385 }1386 appendAllChildren(instance, workInProgress, false, false);1387 mountFundamentalComponent(fundamentalInstance);1388 } else {1389 // We fire update in commit phase1390 const prevProps = fundamentalInstance.props;1391 fundamentalInstance.prevProps = prevProps;1392 fundamentalInstance.props = newProps;1393 fundamentalInstance.currentFiber = workInProgress;1394 if (supportsPersistence) {1395 const instance = cloneFundamentalInstance(fundamentalInstance);1396 fundamentalInstance.instance = instance;1397 appendAllChildren(instance, workInProgress, false, false);1398 }1399 const shouldUpdate = shouldUpdateFundamentalComponent(1400 fundamentalInstance,1401 );1402 if (shouldUpdate) {1403 markUpdate(workInProgress);1404 }1405 }1406 bubbleProperties(workInProgress);1407 return null;1408 }1409 break;1410 }1411 case ScopeComponent: {1412 if (enableScopeAPI) {1413 if (current === null) {1414 const scopeInstance: ReactScopeInstance = createScopeInstance();1415 workInProgress.stateNode = scopeInstance;1416 prepareScopeUpdate(scopeInstance, workInProgress);1417 if (workInProgress.ref !== null) {1418 markRef(workInProgress);1419 markUpdate(workInProgress);1420 }1421 } else {1422 if (workInProgress.ref !== null) {1423 markUpdate(workInProgress);1424 }1425 if (current.ref !== workInProgress.ref) {1426 markRef(workInProgress);1427 }1428 }1429 bubbleProperties(workInProgress);1430 return null;1431 }1432 break;1433 }1434 case Block:1435 if (enableBlocksAPI) {1436 bubbleProperties(workInProgress);1437 return null;1438 }1439 break;1440 case OffscreenComponent:1441 case LegacyHiddenComponent: {1442 popRenderLanes(workInProgress);1443 const nextState: OffscreenState | null = workInProgress.memoizedState;1444 const nextIsHidden = nextState !== null;1445 if (current !== null) {1446 const prevState: OffscreenState | null = current.memoizedState;1447 const prevIsHidden = prevState !== null;1448 if (1449 prevIsHidden !== nextIsHidden &&1450 newProps.mode !== 'unstable-defer-without-hiding'1451 ) {1452 workInProgress.flags |= Update;1453 }1454 }1455 // Don't bubble properties for hidden children.1456 if (1457 !nextIsHidden ||1458 includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||1459 (workInProgress.mode & ConcurrentMode) === NoMode1460 ) {1461 bubbleProperties(workInProgress);1462 }1463 return null;1464 }1465 }1466 invariant(1467 false,1468 'Unknown unit of work tag (%s). This error is likely caused by a bug in ' +1469 'React. Please file an issue.',1470 workInProgress.tag,1471 );1472}...

Full Screen

Full Screen

ReactFiberCompleteWork.old.js

Source:ReactFiberCompleteWork.old.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */9import type {Fiber} from './ReactInternalTypes';10import type {Lanes, Lane} from './ReactFiberLane.old';11import type {ReactScopeInstance, ReactContext} from 'shared/ReactTypes';12import type {FiberRoot} from './ReactInternalTypes';13import type {14 Instance,15 Type,16 Props,17 Container,18 ChildSet,19} from './ReactFiberHostConfig';20import type {21 SuspenseState,22 SuspenseListRenderState,23} from './ReactFiberSuspenseComponent.old';24import type {SuspenseContext} from './ReactFiberSuspenseContext.old';25import type {OffscreenState} from './ReactFiberOffscreenComponent';26import type {Cache, SpawnedCachePool} from './ReactFiberCacheComponent.old';27import {resetWorkInProgressVersions as resetMutableSourceWorkInProgressVersions} from './ReactMutableSource.old';28import {now} from './Scheduler';29import {30 IndeterminateComponent,31 FunctionComponent,32 ClassComponent,33 HostRoot,34 HostComponent,35 HostText,36 HostPortal,37 ContextProvider,38 ContextConsumer,39 ForwardRef,40 Fragment,41 Mode,42 Profiler,43 SuspenseComponent,44 SuspenseListComponent,45 MemoComponent,46 SimpleMemoComponent,47 LazyComponent,48 IncompleteClassComponent,49 ScopeComponent,50 OffscreenComponent,51 LegacyHiddenComponent,52 CacheComponent,53} from './ReactWorkTags';54import {NoMode, ConcurrentMode, ProfileMode} from './ReactTypeOfMode';55import {56 Ref,57 RefStatic,58 Update,59 NoFlags,60 DidCapture,61 Snapshot,62 ChildDeletion,63 StaticMask,64 MutationMask,65} from './ReactFiberFlags';66import invariant from 'shared/invariant';67import {68 createInstance,69 createTextInstance,70 appendInitialChild,71 finalizeInitialChildren,72 prepareUpdate,73 supportsMutation,74 supportsPersistence,75 cloneInstance,76 cloneHiddenInstance,77 cloneHiddenTextInstance,78 createContainerChildSet,79 appendChildToContainerChildSet,80 finalizeContainerChildren,81 preparePortalMount,82 prepareScopeUpdate,83} from './ReactFiberHostConfig';84import {85 getRootHostContainer,86 popHostContext,87 getHostContext,88 popHostContainer,89} from './ReactFiberHostContext.old';90import {91 suspenseStackCursor,92 InvisibleParentSuspenseContext,93 hasSuspenseContext,94 popSuspenseContext,95 pushSuspenseContext,96 setShallowSuspenseContext,97 ForceSuspenseFallback,98 setDefaultShallowSuspenseContext,99} from './ReactFiberSuspenseContext.old';100import {findFirstSuspended} from './ReactFiberSuspenseComponent.old';101import {102 isContextProvider as isLegacyContextProvider,103 popContext as popLegacyContext,104 popTopLevelContextObject as popTopLevelLegacyContextObject,105} from './ReactFiberContext.old';106import {popProvider} from './ReactFiberNewContext.old';107import {108 prepareToHydrateHostInstance,109 prepareToHydrateHostTextInstance,110 prepareToHydrateHostSuspenseInstance,111 popHydrationState,112 resetHydrationState,113 getIsHydrating,114} from './ReactFiberHydrationContext.old';115import {116 enableSuspenseCallback,117 enableSuspenseServerRenderer,118 enableScopeAPI,119 enableProfilerTimer,120 enableCache,121 enableSuspenseLayoutEffectSemantics,122} from 'shared/ReactFeatureFlags';123import {124 renderDidSuspend,125 renderDidSuspendDelayIfPossible,126 renderHasNotSuspendedYet,127 popRenderLanes,128 getRenderTargetTime,129 subtreeRenderLanes,130} from './ReactFiberWorkLoop.old';131import {132 OffscreenLane,133 SomeRetryLane,134 NoLanes,135 includesSomeLane,136 mergeLanes,137} from './ReactFiberLane.old';138import {resetChildFibers} from './ReactChildFiber.old';139import {createScopeInstance} from './ReactFiberScope.old';140import {transferActualDuration} from './ReactProfilerTimer.old';141import {142 popCacheProvider,143 popRootCachePool,144 popCachePool,145} from './ReactFiberCacheComponent.old';146function markUpdate(workInProgress: Fiber) {147 // Tag the fiber with an update effect. This turns a Placement into148 // a PlacementAndUpdate.149 workInProgress.flags |= Update;150}151function markRef(workInProgress: Fiber) {152 workInProgress.flags |= Ref;153 if (enableSuspenseLayoutEffectSemantics) {154 workInProgress.flags |= RefStatic;155 }156}157function hadNoMutationsEffects(current: null | Fiber, completedWork: Fiber) {158 const didBailout = current !== null && current.child === completedWork.child;159 if (didBailout) {160 return true;161 }162 if ((completedWork.flags & ChildDeletion) !== NoFlags) {163 return false;164 }165 // TODO: If we move the `hadNoMutationsEffects` call after `bubbleProperties`166 // then we only have to check the `completedWork.subtreeFlags`.167 let child = completedWork.child;168 while (child !== null) {169 if (170 (child.flags & MutationMask) !== NoFlags ||171 (child.subtreeFlags & MutationMask) !== NoFlags172 ) {173 return false;174 }175 child = child.sibling;176 }177 return true;178}179let appendAllChildren;180let updateHostContainer;181let updateHostComponent;182let updateHostText;183if (supportsMutation) {184 // Mutation mode185 appendAllChildren = function(186 parent: Instance,187 workInProgress: Fiber,188 needsVisibilityToggle: boolean,189 isHidden: boolean,190 ) {191 // We only have the top Fiber that was created but we need recurse down its192 // children to find all the terminal nodes.193 let node = workInProgress.child;194 while (node !== null) {195 if (node.tag === HostComponent || node.tag === HostText) {196 appendInitialChild(parent, node.stateNode);197 } else if (node.tag === HostPortal) {198 // If we have a portal child, then we don't want to traverse199 // down its children. Instead, we'll get insertions from each child in200 // the portal directly.201 } else if (node.child !== null) {202 node.child.return = node;203 node = node.child;204 continue;205 }206 if (node === workInProgress) {207 return;208 }209 while (node.sibling === null) {210 if (node.return === null || node.return === workInProgress) {211 return;212 }213 node = node.return;214 }215 node.sibling.return = node.return;216 node = node.sibling;217 }218 };219 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {220 // Noop221 };222 updateHostComponent = function(223 current: Fiber,224 workInProgress: Fiber,225 type: Type,226 newProps: Props,227 rootContainerInstance: Container,228 ) {229 // If we have an alternate, that means this is an update and we need to230 // schedule a side-effect to do the updates.231 const oldProps = current.memoizedProps;232 if (oldProps === newProps) {233 // In mutation mode, this is sufficient for a bailout because234 // we won't touch this node even if children changed.235 return;236 }237 // If we get updated because one of our children updated, we don't238 // have newProps so we'll have to reuse them.239 // TODO: Split the update API as separate for the props vs. children.240 // Even better would be if children weren't special cased at all tho.241 const instance: Instance = workInProgress.stateNode;242 const currentHostContext = getHostContext();243 // TODO: Experiencing an error where oldProps is null. Suggests a host244 // component is hitting the resume path. Figure out why. Possibly245 // related to `hidden`.246 const updatePayload = prepareUpdate(247 instance,248 type,249 oldProps,250 newProps,251 rootContainerInstance,252 currentHostContext,253 );254 // TODO: Type this specific to this type of component.255 workInProgress.updateQueue = (updatePayload: any);256 // If the update payload indicates that there is a change or if there257 // is a new ref we mark this as an update. All the work is done in commitWork.258 if (updatePayload) {259 markUpdate(workInProgress);260 }261 };262 updateHostText = function(263 current: Fiber,264 workInProgress: Fiber,265 oldText: string,266 newText: string,267 ) {268 // If the text differs, mark it as an update. All the work in done in commitWork.269 if (oldText !== newText) {270 markUpdate(workInProgress);271 }272 };273} else if (supportsPersistence) {274 // Persistent host tree mode275 appendAllChildren = function(276 parent: Instance,277 workInProgress: Fiber,278 needsVisibilityToggle: boolean,279 isHidden: boolean,280 ) {281 // We only have the top Fiber that was created but we need recurse down its282 // children to find all the terminal nodes.283 let node = workInProgress.child;284 while (node !== null) {285 // eslint-disable-next-line no-labels286 branches: if (node.tag === HostComponent) {287 let instance = node.stateNode;288 if (needsVisibilityToggle && isHidden) {289 // This child is inside a timed out tree. Hide it.290 const props = node.memoizedProps;291 const type = node.type;292 instance = cloneHiddenInstance(instance, type, props, node);293 }294 appendInitialChild(parent, instance);295 } else if (node.tag === HostText) {296 let instance = node.stateNode;297 if (needsVisibilityToggle && isHidden) {298 // This child is inside a timed out tree. Hide it.299 const text = node.memoizedProps;300 instance = cloneHiddenTextInstance(instance, text, node);301 }302 appendInitialChild(parent, instance);303 } else if (node.tag === HostPortal) {304 // If we have a portal child, then we don't want to traverse305 // down its children. Instead, we'll get insertions from each child in306 // the portal directly.307 } else if (node.tag === SuspenseComponent) {308 if ((node.flags & Update) !== NoFlags) {309 // Need to toggle the visibility of the primary children.310 const newIsHidden = node.memoizedState !== null;311 if (newIsHidden) {312 const primaryChildParent = node.child;313 if (primaryChildParent !== null) {314 if (primaryChildParent.child !== null) {315 primaryChildParent.child.return = primaryChildParent;316 appendAllChildren(317 parent,318 primaryChildParent,319 true,320 newIsHidden,321 );322 }323 const fallbackChildParent = primaryChildParent.sibling;324 if (fallbackChildParent !== null) {325 fallbackChildParent.return = node;326 node = fallbackChildParent;327 continue;328 }329 }330 }331 }332 if (node.child !== null) {333 // Continue traversing like normal334 node.child.return = node;335 node = node.child;336 continue;337 }338 } else if (node.child !== null) {339 node.child.return = node;340 node = node.child;341 continue;342 }343 // $FlowFixMe This is correct but Flow is confused by the labeled break.344 node = (node: Fiber);345 if (node === workInProgress) {346 return;347 }348 while (node.sibling === null) {349 if (node.return === null || node.return === workInProgress) {350 return;351 }352 node = node.return;353 }354 node.sibling.return = node.return;355 node = node.sibling;356 }357 };358 // An unfortunate fork of appendAllChildren because we have two different parent types.359 const appendAllChildrenToContainer = function(360 containerChildSet: ChildSet,361 workInProgress: Fiber,362 needsVisibilityToggle: boolean,363 isHidden: boolean,364 ) {365 // We only have the top Fiber that was created but we need recurse down its366 // children to find all the terminal nodes.367 let node = workInProgress.child;368 while (node !== null) {369 // eslint-disable-next-line no-labels370 branches: if (node.tag === HostComponent) {371 let instance = node.stateNode;372 if (needsVisibilityToggle && isHidden) {373 // This child is inside a timed out tree. Hide it.374 const props = node.memoizedProps;375 const type = node.type;376 instance = cloneHiddenInstance(instance, type, props, node);377 }378 appendChildToContainerChildSet(containerChildSet, instance);379 } else if (node.tag === HostText) {380 let instance = node.stateNode;381 if (needsVisibilityToggle && isHidden) {382 // This child is inside a timed out tree. Hide it.383 const text = node.memoizedProps;384 instance = cloneHiddenTextInstance(instance, text, node);385 }386 appendChildToContainerChildSet(containerChildSet, instance);387 } else if (node.tag === HostPortal) {388 // If we have a portal child, then we don't want to traverse389 // down its children. Instead, we'll get insertions from each child in390 // the portal directly.391 } else if (node.tag === SuspenseComponent) {392 if ((node.flags & Update) !== NoFlags) {393 // Need to toggle the visibility of the primary children.394 const newIsHidden = node.memoizedState !== null;395 if (newIsHidden) {396 const primaryChildParent = node.child;397 if (primaryChildParent !== null) {398 if (primaryChildParent.child !== null) {399 primaryChildParent.child.return = primaryChildParent;400 appendAllChildrenToContainer(401 containerChildSet,402 primaryChildParent,403 true,404 newIsHidden,405 );406 }407 const fallbackChildParent = primaryChildParent.sibling;408 if (fallbackChildParent !== null) {409 fallbackChildParent.return = node;410 node = fallbackChildParent;411 continue;412 }413 }414 }415 }416 if (node.child !== null) {417 // Continue traversing like normal418 node.child.return = node;419 node = node.child;420 continue;421 }422 } else if (node.child !== null) {423 node.child.return = node;424 node = node.child;425 continue;426 }427 // $FlowFixMe This is correct but Flow is confused by the labeled break.428 node = (node: Fiber);429 if (node === workInProgress) {430 return;431 }432 while (node.sibling === null) {433 if (node.return === null || node.return === workInProgress) {434 return;435 }436 node = node.return;437 }438 node.sibling.return = node.return;439 node = node.sibling;440 }441 };442 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {443 const portalOrRoot: {444 containerInfo: Container,445 pendingChildren: ChildSet,446 ...447 } = workInProgress.stateNode;448 const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);449 if (childrenUnchanged) {450 // No changes, just reuse the existing instance.451 } else {452 const container = portalOrRoot.containerInfo;453 const newChildSet = createContainerChildSet(container);454 // If children might have changed, we have to add them all to the set.455 appendAllChildrenToContainer(newChildSet, workInProgress, false, false);456 portalOrRoot.pendingChildren = newChildSet;457 // Schedule an update on the container to swap out the container.458 markUpdate(workInProgress);459 finalizeContainerChildren(container, newChildSet);460 }461 };462 updateHostComponent = function(463 current: Fiber,464 workInProgress: Fiber,465 type: Type,466 newProps: Props,467 rootContainerInstance: Container,468 ) {469 const currentInstance = current.stateNode;470 const oldProps = current.memoizedProps;471 // If there are no effects associated with this node, then none of our children had any updates.472 // This guarantees that we can reuse all of them.473 const childrenUnchanged = hadNoMutationsEffects(current, workInProgress);474 if (childrenUnchanged && oldProps === newProps) {475 // No changes, just reuse the existing instance.476 // Note that this might release a previous clone.477 workInProgress.stateNode = currentInstance;478 return;479 }480 const recyclableInstance: Instance = workInProgress.stateNode;481 const currentHostContext = getHostContext();482 let updatePayload = null;483 if (oldProps !== newProps) {484 updatePayload = prepareUpdate(485 recyclableInstance,486 type,487 oldProps,488 newProps,489 rootContainerInstance,490 currentHostContext,491 );492 }493 if (childrenUnchanged && updatePayload === null) {494 // No changes, just reuse the existing instance.495 // Note that this might release a previous clone.496 workInProgress.stateNode = currentInstance;497 return;498 }499 const newInstance = cloneInstance(500 currentInstance,501 updatePayload,502 type,503 oldProps,504 newProps,505 workInProgress,506 childrenUnchanged,507 recyclableInstance,508 );509 if (510 finalizeInitialChildren(511 newInstance,512 type,513 newProps,514 rootContainerInstance,515 currentHostContext,516 )517 ) {518 markUpdate(workInProgress);519 }520 workInProgress.stateNode = newInstance;521 if (childrenUnchanged) {522 // If there are no other effects in this tree, we need to flag this node as having one.523 // Even though we're not going to use it for anything.524 // Otherwise parents won't know that there are new children to propagate upwards.525 markUpdate(workInProgress);526 } else {527 // If children might have changed, we have to add them all to the set.528 appendAllChildren(newInstance, workInProgress, false, false);529 }530 };531 updateHostText = function(532 current: Fiber,533 workInProgress: Fiber,534 oldText: string,535 newText: string,536 ) {537 if (oldText !== newText) {538 // If the text content differs, we'll create a new text instance for it.539 const rootContainerInstance = getRootHostContainer();540 const currentHostContext = getHostContext();541 workInProgress.stateNode = createTextInstance(542 newText,543 rootContainerInstance,544 currentHostContext,545 workInProgress,546 );547 // We'll have to mark it as having an effect, even though we won't use the effect for anything.548 // This lets the parents know that at least one of their children has changed.549 markUpdate(workInProgress);550 } else {551 workInProgress.stateNode = current.stateNode;552 }553 };554} else {555 // No host operations556 updateHostContainer = function(current: null | Fiber, workInProgress: Fiber) {557 // Noop558 };559 updateHostComponent = function(560 current: Fiber,561 workInProgress: Fiber,562 type: Type,563 newProps: Props,564 rootContainerInstance: Container,565 ) {566 // Noop567 };568 updateHostText = function(569 current: Fiber,570 workInProgress: Fiber,571 oldText: string,572 newText: string,573 ) {574 // Noop575 };576}577function cutOffTailIfNeeded(578 renderState: SuspenseListRenderState,579 hasRenderedATailFallback: boolean,580) {581 if (getIsHydrating()) {582 // If we're hydrating, we should consume as many items as we can583 // so we don't leave any behind.584 return;585 }586 switch (renderState.tailMode) {587 case 'hidden': {588 // Any insertions at the end of the tail list after this point589 // should be invisible. If there are already mounted boundaries590 // anything before them are not considered for collapsing.591 // Therefore we need to go through the whole tail to find if592 // there are any.593 let tailNode = renderState.tail;594 let lastTailNode = null;595 while (tailNode !== null) {596 if (tailNode.alternate !== null) {597 lastTailNode = tailNode;598 }599 tailNode = tailNode.sibling;600 }601 // Next we're simply going to delete all insertions after the602 // last rendered item.603 if (lastTailNode === null) {604 // All remaining items in the tail are insertions.605 renderState.tail = null;606 } else {607 // Detach the insertion after the last node that was already608 // inserted.609 lastTailNode.sibling = null;610 }611 break;612 }613 case 'collapsed': {614 // Any insertions at the end of the tail list after this point615 // should be invisible. If there are already mounted boundaries616 // anything before them are not considered for collapsing.617 // Therefore we need to go through the whole tail to find if618 // there are any.619 let tailNode = renderState.tail;620 let lastTailNode = null;621 while (tailNode !== null) {622 if (tailNode.alternate !== null) {623 lastTailNode = tailNode;624 }625 tailNode = tailNode.sibling;626 }627 // Next we're simply going to delete all insertions after the628 // last rendered item.629 if (lastTailNode === null) {630 // All remaining items in the tail are insertions.631 if (!hasRenderedATailFallback && renderState.tail !== null) {632 // We suspended during the head. We want to show at least one633 // row at the tail. So we'll keep on and cut off the rest.634 renderState.tail.sibling = null;635 } else {636 renderState.tail = null;637 }638 } else {639 // Detach the insertion after the last node that was already640 // inserted.641 lastTailNode.sibling = null;642 }643 break;644 }645 }646}647function bubbleProperties(completedWork: Fiber) {648 const didBailout =649 completedWork.alternate !== null &&650 completedWork.alternate.child === completedWork.child;651 let newChildLanes = NoLanes;652 let subtreeFlags = NoFlags;653 if (!didBailout) {654 // Bubble up the earliest expiration time.655 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {656 // In profiling mode, resetChildExpirationTime is also used to reset657 // profiler durations.658 let actualDuration = completedWork.actualDuration;659 let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);660 let child = completedWork.child;661 while (child !== null) {662 newChildLanes = mergeLanes(663 newChildLanes,664 mergeLanes(child.lanes, child.childLanes),665 );666 subtreeFlags |= child.subtreeFlags;667 subtreeFlags |= child.flags;668 // When a fiber is cloned, its actualDuration is reset to 0. This value will669 // only be updated if work is done on the fiber (i.e. it doesn't bailout).670 // When work is done, it should bubble to the parent's actualDuration. If671 // the fiber has not been cloned though, (meaning no work was done), then672 // this value will reflect the amount of time spent working on a previous673 // render. In that case it should not bubble. We determine whether it was674 // cloned by comparing the child pointer.675 actualDuration += child.actualDuration;676 treeBaseDuration += child.treeBaseDuration;677 child = child.sibling;678 }679 completedWork.actualDuration = actualDuration;680 completedWork.treeBaseDuration = treeBaseDuration;681 } else {682 let child = completedWork.child;683 while (child !== null) {684 newChildLanes = mergeLanes(685 newChildLanes,686 mergeLanes(child.lanes, child.childLanes),687 );688 subtreeFlags |= child.subtreeFlags;689 subtreeFlags |= child.flags;690 // Update the return pointer so the tree is consistent. This is a code691 // smell because it assumes the commit phase is never concurrent with692 // the render phase. Will address during refactor to alternate model.693 child.return = completedWork;694 child = child.sibling;695 }696 }697 completedWork.subtreeFlags |= subtreeFlags;698 } else {699 // Bubble up the earliest expiration time.700 if (enableProfilerTimer && (completedWork.mode & ProfileMode) !== NoMode) {701 // In profiling mode, resetChildExpirationTime is also used to reset702 // profiler durations.703 let treeBaseDuration = ((completedWork.selfBaseDuration: any): number);704 let child = completedWork.child;705 while (child !== null) {706 newChildLanes = mergeLanes(707 newChildLanes,708 mergeLanes(child.lanes, child.childLanes),709 );710 // "Static" flags share the lifetime of the fiber/hook they belong to,711 // so we should bubble those up even during a bailout. All the other712 // flags have a lifetime only of a single render + commit, so we should713 // ignore them.714 subtreeFlags |= child.subtreeFlags & StaticMask;715 subtreeFlags |= child.flags & StaticMask;716 treeBaseDuration += child.treeBaseDuration;717 child = child.sibling;718 }719 completedWork.treeBaseDuration = treeBaseDuration;720 } else {721 let child = completedWork.child;722 while (child !== null) {723 newChildLanes = mergeLanes(724 newChildLanes,725 mergeLanes(child.lanes, child.childLanes),726 );727 // "Static" flags share the lifetime of the fiber/hook they belong to,728 // so we should bubble those up even during a bailout. All the other729 // flags have a lifetime only of a single render + commit, so we should730 // ignore them.731 subtreeFlags |= child.subtreeFlags & StaticMask;732 subtreeFlags |= child.flags & StaticMask;733 // Update the return pointer so the tree is consistent. This is a code734 // smell because it assumes the commit phase is never concurrent with735 // the render phase. Will address during refactor to alternate model.736 child.return = completedWork;737 child = child.sibling;738 }739 }740 completedWork.subtreeFlags |= subtreeFlags;741 }742 completedWork.childLanes = newChildLanes;743 return didBailout;744}745function completeWork(746 current: Fiber | null,747 workInProgress: Fiber,748 renderLanes: Lanes,749): Fiber | null {750 const newProps = workInProgress.pendingProps;751 switch (workInProgress.tag) {752 case IndeterminateComponent:753 case LazyComponent:754 case SimpleMemoComponent:755 case FunctionComponent:756 case ForwardRef:757 case Fragment:758 case Mode:759 case Profiler:760 case ContextConsumer:761 case MemoComponent:762 bubbleProperties(workInProgress);763 return null;764 case ClassComponent: {765 const Component = workInProgress.type;766 if (isLegacyContextProvider(Component)) {767 popLegacyContext(workInProgress);768 }769 bubbleProperties(workInProgress);770 return null;771 }772 case HostRoot: {773 const fiberRoot = (workInProgress.stateNode: FiberRoot);774 if (enableCache) {775 popRootCachePool(fiberRoot, renderLanes);776 const cache: Cache = workInProgress.memoizedState.cache;777 popCacheProvider(workInProgress, cache);778 }779 popHostContainer(workInProgress);780 popTopLevelLegacyContextObject(workInProgress);781 resetMutableSourceWorkInProgressVersions();782 if (fiberRoot.pendingContext) {783 fiberRoot.context = fiberRoot.pendingContext;784 fiberRoot.pendingContext = null;785 }786 if (current === null || current.child === null) {787 // If we hydrated, pop so that we can delete any remaining children788 // that weren't hydrated.789 const wasHydrated = popHydrationState(workInProgress);790 if (wasHydrated) {791 // If we hydrated, then we'll need to schedule an update for792 // the commit side-effects on the root.793 markUpdate(workInProgress);794 } else if (!fiberRoot.hydrate) {795 // Schedule an effect to clear this container at the start of the next commit.796 // This handles the case of React rendering into a container with previous children.797 // It's also safe to do for updates too, because current.child would only be null798 // if the previous render was null (so the the container would already be empty).799 workInProgress.flags |= Snapshot;800 }801 }802 updateHostContainer(current, workInProgress);803 bubbleProperties(workInProgress);804 return null;805 }806 case HostComponent: {807 popHostContext(workInProgress);808 const rootContainerInstance = getRootHostContainer();809 const type = workInProgress.type;810 if (current !== null && workInProgress.stateNode != null) {811 updateHostComponent(812 current,813 workInProgress,814 type,815 newProps,816 rootContainerInstance,817 );818 if (current.ref !== workInProgress.ref) {819 markRef(workInProgress);820 }821 } else {822 if (!newProps) {823 invariant(824 workInProgress.stateNode !== null,825 'We must have new props for new mounts. This error is likely ' +826 'caused by a bug in React. Please file an issue.',827 );828 // This can happen when we abort work.829 bubbleProperties(workInProgress);830 return null;831 }832 const currentHostContext = getHostContext();833 // TODO: Move createInstance to beginWork and keep it on a context834 // "stack" as the parent. Then append children as we go in beginWork835 // or completeWork depending on whether we want to add them top->down or836 // bottom->up. Top->down is faster in IE11.837 const wasHydrated = popHydrationState(workInProgress);838 if (wasHydrated) {839 // TODO: Move this and createInstance step into the beginPhase840 // to consolidate.841 if (842 prepareToHydrateHostInstance(843 workInProgress,844 rootContainerInstance,845 currentHostContext,846 )847 ) {848 // If changes to the hydrated node need to be applied at the849 // commit-phase we mark this as such.850 markUpdate(workInProgress);851 }852 } else {853 const instance = createInstance(854 type,855 newProps,856 rootContainerInstance,857 currentHostContext,858 workInProgress,859 );860 appendAllChildren(instance, workInProgress, false, false);861 workInProgress.stateNode = instance;862 // Certain renderers require commit-time effects for initial mount.863 // (eg DOM renderer supports auto-focus for certain elements).864 // Make sure such renderers get scheduled for later work.865 if (866 finalizeInitialChildren(867 instance,868 type,869 newProps,870 rootContainerInstance,871 currentHostContext,872 )873 ) {874 markUpdate(workInProgress);875 }876 }877 if (workInProgress.ref !== null) {878 // If there is a ref on a host node we need to schedule a callback879 markRef(workInProgress);880 }881 }882 bubbleProperties(workInProgress);883 return null;884 }885 case HostText: {886 const newText = newProps;887 if (current && workInProgress.stateNode != null) {888 const oldText = current.memoizedProps;889 // If we have an alternate, that means this is an update and we need890 // to schedule a side-effect to do the updates.891 updateHostText(current, workInProgress, oldText, newText);892 } else {893 if (typeof newText !== 'string') {894 invariant(895 workInProgress.stateNode !== null,896 'We must have new props for new mounts. This error is likely ' +897 'caused by a bug in React. Please file an issue.',898 );899 // This can happen when we abort work.900 }901 const rootContainerInstance = getRootHostContainer();902 const currentHostContext = getHostContext();903 const wasHydrated = popHydrationState(workInProgress);904 if (wasHydrated) {905 if (prepareToHydrateHostTextInstance(workInProgress)) {906 markUpdate(workInProgress);907 }908 } else {909 workInProgress.stateNode = createTextInstance(910 newText,911 rootContainerInstance,912 currentHostContext,913 workInProgress,914 );915 }916 }917 bubbleProperties(workInProgress);918 return null;919 }920 case SuspenseComponent: {921 popSuspenseContext(workInProgress);922 const nextState: null | SuspenseState = workInProgress.memoizedState;923 if (enableSuspenseServerRenderer) {924 if (nextState !== null && nextState.dehydrated !== null) {925 if (current === null) {926 const wasHydrated = popHydrationState(workInProgress);927 invariant(928 wasHydrated,929 'A dehydrated suspense component was completed without a hydrated node. ' +930 'This is probably a bug in React.',931 );932 prepareToHydrateHostSuspenseInstance(workInProgress);933 bubbleProperties(workInProgress);934 if (enableProfilerTimer) {935 if ((workInProgress.mode & ProfileMode) !== NoMode) {936 const isTimedOutSuspense = nextState !== null;937 if (isTimedOutSuspense) {938 // Don't count time spent in a timed out Suspense subtree as part of the base duration.939 const primaryChildFragment = workInProgress.child;940 if (primaryChildFragment !== null) {941 // $FlowFixMe Flow doesn't support type casting in combination with the -= operator942 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);943 }944 }945 }946 }947 return null;948 } else {949 // We should never have been in a hydration state if we didn't have a current.950 // However, in some of those paths, we might have reentered a hydration state951 // and then we might be inside a hydration state. In that case, we'll need to exit out of it.952 resetHydrationState();953 if ((workInProgress.flags & DidCapture) === NoFlags) {954 // This boundary did not suspend so it's now hydrated and unsuspended.955 workInProgress.memoizedState = null;956 }957 // If nothing suspended, we need to schedule an effect to mark this boundary958 // as having hydrated so events know that they're free to be invoked.959 // It's also a signal to replay events and the suspense callback.960 // If something suspended, schedule an effect to attach retry listeners.961 // So we might as well always mark this.962 workInProgress.flags |= Update;963 bubbleProperties(workInProgress);964 if (enableProfilerTimer) {965 if ((workInProgress.mode & ProfileMode) !== NoMode) {966 const isTimedOutSuspense = nextState !== null;967 if (isTimedOutSuspense) {968 // Don't count time spent in a timed out Suspense subtree as part of the base duration.969 const primaryChildFragment = workInProgress.child;970 if (primaryChildFragment !== null) {971 // $FlowFixMe Flow doesn't support type casting in combination with the -= operator972 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);973 }974 }975 }976 }977 return null;978 }979 }980 }981 if ((workInProgress.flags & DidCapture) !== NoFlags) {982 // Something suspended. Re-render with the fallback children.983 workInProgress.lanes = renderLanes;984 // Do not reset the effect list.985 if (986 enableProfilerTimer &&987 (workInProgress.mode & ProfileMode) !== NoMode988 ) {989 transferActualDuration(workInProgress);990 }991 // Don't bubble properties in this case.992 return workInProgress;993 }994 const nextDidTimeout = nextState !== null;995 let prevDidTimeout = false;996 if (current === null) {997 if (workInProgress.memoizedProps.fallback !== undefined) {998 popHydrationState(workInProgress);999 }1000 } else {1001 const prevState: null | SuspenseState = current.memoizedState;1002 prevDidTimeout = prevState !== null;1003 }1004 if (nextDidTimeout && !prevDidTimeout) {1005 // TODO: This will still suspend a synchronous tree if anything1006 // in the concurrent tree already suspended during this render.1007 // This is a known bug.1008 if ((workInProgress.mode & ConcurrentMode) !== NoMode) {1009 // TODO: Move this back to throwException because this is too late1010 // if this is a large tree which is common for initial loads. We1011 // don't know if we should restart a render or not until we get1012 // this marker, and this is too late.1013 // If this render already had a ping or lower pri updates,1014 // and this is the first time we know we're going to suspend we1015 // should be able to immediately restart from within throwException.1016 const hasInvisibleChildContext =1017 current === null &&1018 workInProgress.memoizedProps.unstable_avoidThisFallback !== true;1019 if (1020 hasInvisibleChildContext ||1021 hasSuspenseContext(1022 suspenseStackCursor.current,1023 (InvisibleParentSuspenseContext: SuspenseContext),1024 )1025 ) {1026 // If this was in an invisible tree or a new render, then showing1027 // this boundary is ok.1028 renderDidSuspend();1029 } else {1030 // Otherwise, we're going to have to hide content so we should1031 // suspend for longer if possible.1032 renderDidSuspendDelayIfPossible();1033 }1034 }1035 }1036 if (supportsPersistence) {1037 // TODO: Only schedule updates if not prevDidTimeout.1038 if (nextDidTimeout) {1039 // If this boundary just timed out, schedule an effect to attach a1040 // retry listener to the promise. This flag is also used to hide the1041 // primary children.1042 workInProgress.flags |= Update;1043 }1044 }1045 if (supportsMutation) {1046 // TODO: Only schedule updates if these values are non equal, i.e. it changed.1047 if (nextDidTimeout || prevDidTimeout) {1048 // If this boundary just timed out, schedule an effect to attach a1049 // retry listener to the promise. This flag is also used to hide the1050 // primary children. In mutation mode, we also need the flag to1051 // *unhide* children that were previously hidden, so check if this1052 // is currently timed out, too.1053 workInProgress.flags |= Update;1054 }1055 }1056 if (1057 enableSuspenseCallback &&1058 workInProgress.updateQueue !== null &&1059 workInProgress.memoizedProps.suspenseCallback != null1060 ) {1061 // Always notify the callback1062 workInProgress.flags |= Update;1063 }1064 bubbleProperties(workInProgress);1065 if (enableProfilerTimer) {1066 if ((workInProgress.mode & ProfileMode) !== NoMode) {1067 if (nextDidTimeout) {1068 // Don't count time spent in a timed out Suspense subtree as part of the base duration.1069 const primaryChildFragment = workInProgress.child;1070 if (primaryChildFragment !== null) {1071 // $FlowFixMe Flow doesn't support type casting in combination with the -= operator1072 workInProgress.treeBaseDuration -= ((primaryChildFragment.treeBaseDuration: any): number);1073 }1074 }1075 }1076 }1077 return null;1078 }1079 case HostPortal:1080 popHostContainer(workInProgress);1081 updateHostContainer(current, workInProgress);1082 if (current === null) {1083 preparePortalMount(workInProgress.stateNode.containerInfo);1084 }1085 bubbleProperties(workInProgress);1086 return null;1087 case ContextProvider:1088 // Pop provider fiber1089 const context: ReactContext<any> = workInProgress.type._context;1090 popProvider(context, workInProgress);1091 bubbleProperties(workInProgress);1092 return null;1093 case IncompleteClassComponent: {1094 // Same as class component case. I put it down here so that the tags are1095 // sequential to ensure this switch is compiled to a jump table.1096 const Component = workInProgress.type;1097 if (isLegacyContextProvider(Component)) {1098 popLegacyContext(workInProgress);1099 }1100 bubbleProperties(workInProgress);1101 return null;1102 }1103 case SuspenseListComponent: {1104 popSuspenseContext(workInProgress);1105 const renderState: null | SuspenseListRenderState =1106 workInProgress.memoizedState;1107 if (renderState === null) {1108 // We're running in the default, "independent" mode.1109 // We don't do anything in this mode.1110 bubbleProperties(workInProgress);1111 return null;1112 }1113 let didSuspendAlready = (workInProgress.flags & DidCapture) !== NoFlags;1114 const renderedTail = renderState.rendering;1115 if (renderedTail === null) {1116 // We just rendered the head.1117 if (!didSuspendAlready) {1118 // This is the first pass. We need to figure out if anything is still1119 // suspended in the rendered set.1120 // If new content unsuspended, but there's still some content that1121 // didn't. Then we need to do a second pass that forces everything1122 // to keep showing their fallbacks.1123 // We might be suspended if something in this render pass suspended, or1124 // something in the previous committed pass suspended. Otherwise,1125 // there's no chance so we can skip the expensive call to1126 // findFirstSuspended.1127 const cannotBeSuspended =1128 renderHasNotSuspendedYet() &&1129 (current === null || (current.flags & DidCapture) === NoFlags);1130 if (!cannotBeSuspended) {1131 let row = workInProgress.child;1132 while (row !== null) {1133 const suspended = findFirstSuspended(row);1134 if (suspended !== null) {1135 didSuspendAlready = true;1136 workInProgress.flags |= DidCapture;1137 cutOffTailIfNeeded(renderState, false);1138 // If this is a newly suspended tree, it might not get committed as1139 // part of the second pass. In that case nothing will subscribe to1140 // its thennables. Instead, we'll transfer its thennables to the1141 // SuspenseList so that it can retry if they resolve.1142 // There might be multiple of these in the list but since we're1143 // going to wait for all of them anyway, it doesn't really matter1144 // which ones gets to ping. In theory we could get clever and keep1145 // track of how many dependencies remain but it gets tricky because1146 // in the meantime, we can add/remove/change items and dependencies.1147 // We might bail out of the loop before finding any but that1148 // doesn't matter since that means that the other boundaries that1149 // we did find already has their listeners attached.1150 const newThennables = suspended.updateQueue;1151 if (newThennables !== null) {1152 workInProgress.updateQueue = newThennables;1153 workInProgress.flags |= Update;1154 }1155 // Rerender the whole list, but this time, we'll force fallbacks1156 // to stay in place.1157 // Reset the effect flags before doing the second pass since that's now invalid.1158 // Reset the child fibers to their original state.1159 workInProgress.subtreeFlags = NoFlags;1160 resetChildFibers(workInProgress, renderLanes);1161 // Set up the Suspense Context to force suspense and immediately1162 // rerender the children.1163 pushSuspenseContext(1164 workInProgress,1165 setShallowSuspenseContext(1166 suspenseStackCursor.current,1167 ForceSuspenseFallback,1168 ),1169 );1170 // Don't bubble properties in this case.1171 return workInProgress.child;1172 }1173 row = row.sibling;1174 }1175 }1176 if (renderState.tail !== null && now() > getRenderTargetTime()) {1177 // We have already passed our CPU deadline but we still have rows1178 // left in the tail. We'll just give up further attempts to render1179 // the main content and only render fallbacks.1180 workInProgress.flags |= DidCapture;1181 didSuspendAlready = true;1182 cutOffTailIfNeeded(renderState, false);1183 // Since nothing actually suspended, there will nothing to ping this1184 // to get it started back up to attempt the next item. While in terms1185 // of priority this work has the same priority as this current render,1186 // it's not part of the same transition once the transition has1187 // committed. If it's sync, we still want to yield so that it can be1188 // painted. Conceptually, this is really the same as pinging.1189 // We can use any RetryLane even if it's the one currently rendering1190 // since we're leaving it behind on this node.1191 workInProgress.lanes = SomeRetryLane;1192 }1193 } else {1194 cutOffTailIfNeeded(renderState, false);1195 }1196 // Next we're going to render the tail.1197 } else {1198 // Append the rendered row to the child list.1199 if (!didSuspendAlready) {1200 const suspended = findFirstSuspended(renderedTail);1201 if (suspended !== null) {1202 workInProgress.flags |= DidCapture;1203 didSuspendAlready = true;1204 // Ensure we transfer the update queue to the parent so that it doesn't1205 // get lost if this row ends up dropped during a second pass.1206 const newThennables = suspended.updateQueue;1207 if (newThennables !== null) {1208 workInProgress.updateQueue = newThennables;1209 workInProgress.flags |= Update;1210 }1211 cutOffTailIfNeeded(renderState, true);1212 // This might have been modified.1213 if (1214 renderState.tail === null &&1215 renderState.tailMode === 'hidden' &&1216 !renderedTail.alternate &&1217 !getIsHydrating() // We don't cut it if we're hydrating.1218 ) {1219 // We're done.1220 bubbleProperties(workInProgress);1221 return null;1222 }1223 } else if (1224 // The time it took to render last row is greater than the remaining1225 // time we have to render. So rendering one more row would likely1226 // exceed it.1227 now() * 2 - renderState.renderingStartTime >1228 getRenderTargetTime() &&1229 renderLanes !== OffscreenLane1230 ) {1231 // We have now passed our CPU deadline and we'll just give up further1232 // attempts to render the main content and only render fallbacks.1233 // The assumption is that this is usually faster.1234 workInProgress.flags |= DidCapture;1235 didSuspendAlready = true;1236 cutOffTailIfNeeded(renderState, false);1237 // Since nothing actually suspended, there will nothing to ping this1238 // to get it started back up to attempt the next item. While in terms1239 // of priority this work has the same priority as this current render,1240 // it's not part of the same transition once the transition has1241 // committed. If it's sync, we still want to yield so that it can be1242 // painted. Conceptually, this is really the same as pinging.1243 // We can use any RetryLane even if it's the one currently rendering1244 // since we're leaving it behind on this node.1245 workInProgress.lanes = SomeRetryLane;1246 }1247 }1248 if (renderState.isBackwards) {1249 // The effect list of the backwards tail will have been added1250 // to the end. This breaks the guarantee that life-cycles fire in1251 // sibling order but that isn't a strong guarantee promised by React.1252 // Especially since these might also just pop in during future commits.1253 // Append to the beginning of the list.1254 renderedTail.sibling = workInProgress.child;1255 workInProgress.child = renderedTail;1256 } else {1257 const previousSibling = renderState.last;1258 if (previousSibling !== null) {1259 previousSibling.sibling = renderedTail;1260 } else {1261 workInProgress.child = renderedTail;1262 }1263 renderState.last = renderedTail;1264 }1265 }1266 if (renderState.tail !== null) {1267 // We still have tail rows to render.1268 // Pop a row.1269 const next = renderState.tail;1270 renderState.rendering = next;1271 renderState.tail = next.sibling;1272 renderState.renderingStartTime = now();1273 next.sibling = null;1274 // Restore the context.1275 // TODO: We can probably just avoid popping it instead and only1276 // setting it the first time we go from not suspended to suspended.1277 let suspenseContext = suspenseStackCursor.current;1278 if (didSuspendAlready) {1279 suspenseContext = setShallowSuspenseContext(1280 suspenseContext,1281 ForceSuspenseFallback,1282 );1283 } else {1284 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);1285 }1286 pushSuspenseContext(workInProgress, suspenseContext);1287 // Do a pass over the next row.1288 // Don't bubble properties in this case.1289 return next;1290 }1291 bubbleProperties(workInProgress);1292 return null;1293 }1294 case ScopeComponent: {1295 if (enableScopeAPI) {1296 if (current === null) {1297 const scopeInstance: ReactScopeInstance = createScopeInstance();1298 workInProgress.stateNode = scopeInstance;1299 prepareScopeUpdate(scopeInstance, workInProgress);1300 if (workInProgress.ref !== null) {1301 markRef(workInProgress);1302 markUpdate(workInProgress);1303 }1304 } else {1305 if (workInProgress.ref !== null) {1306 markUpdate(workInProgress);1307 }1308 if (current.ref !== workInProgress.ref) {1309 markRef(workInProgress);1310 }1311 }1312 bubbleProperties(workInProgress);1313 return null;1314 }1315 break;1316 }1317 case OffscreenComponent:1318 case LegacyHiddenComponent: {1319 popRenderLanes(workInProgress);1320 const nextState: OffscreenState | null = workInProgress.memoizedState;1321 const nextIsHidden = nextState !== null;1322 if (current !== null) {1323 const prevState: OffscreenState | null = current.memoizedState;1324 const prevIsHidden = prevState !== null;1325 if (1326 prevIsHidden !== nextIsHidden &&1327 newProps.mode !== 'unstable-defer-without-hiding'1328 ) {1329 workInProgress.flags |= Update;1330 }1331 }1332 // Don't bubble properties for hidden children.1333 if (1334 !nextIsHidden ||1335 includesSomeLane(subtreeRenderLanes, (OffscreenLane: Lane)) ||1336 (workInProgress.mode & ConcurrentMode) === NoMode1337 ) {1338 bubbleProperties(workInProgress);1339 }1340 if (enableCache) {1341 const spawnedCachePool: SpawnedCachePool | null = (workInProgress.updateQueue: any);1342 if (spawnedCachePool !== null) {1343 popCachePool(workInProgress);1344 }1345 }1346 return null;1347 }1348 case CacheComponent: {1349 if (enableCache) {1350 const cache: Cache = workInProgress.memoizedState.cache;1351 popCacheProvider(workInProgress, cache);1352 bubbleProperties(workInProgress);1353 return null;1354 }1355 }1356 }1357 invariant(1358 false,1359 'Unknown unit of work tag (%s). This error is likely caused by a bug in ' +1360 'React. Please file an issue.',1361 workInProgress.tag,1362 );1363}...

Full Screen

Full Screen

ReactFiberWorkLoop.js

Source:ReactFiberWorkLoop.js Github

copy

Full Screen

...280}281// 将child fiber的expirationTime冒泡到父级282// 这样在父级就能直到子孙中优先级最高到expirationTime283// 配合 bailoutOnAlreadyFinishedWork 的优化路径284function resetChildExpirationTime(completedWork) {285 let newChildExpirationTime = NoWork;286 let child = completedWork.child;287 while (child) {288 const childUpdateExpirationTime = child.expirationTime;289 const childChildExpirationTime = child.childChildExpirationTime;290 if (childUpdateExpirationTime > newChildExpirationTime) {291 newChildExpirationTime = childUpdateExpirationTime;292 }293 if (childChildExpirationTime > newChildExpirationTime) {294 newChildExpirationTime = childChildExpirationTime;295 }296 child = child.sibling;297 }298 completedWork.childExpirationTime = newChildExpirationTime;299}300// 由于一定是beginWork返回null才会执行completeUnitOfWork,而beginWork始终创建并返回fiber.child301// 所以传入的fiber一定是某个子树的叶子节点302// 返回节点的兄弟节点(如果存在),不存在兄弟节点时递归上一级303function completeUnitOfWork(unitOfWork) {304 workInProgress = unitOfWork;305 do {306 const current = workInProgress.alternate;307 const returnFiber = workInProgress.return;308 // if (!(workInProgress.effectTag & Incomplete)) {309 if (true) {310 // 该fiber未抛出错误311 // 当前总会返回null312 let next = completeWork(current, workInProgress);313 resetChildExpirationTime(workInProgress);314 if (next) {315 return next;316 }317 if (returnFiber) {318 // if (returnFiber && !(returnFiber.effectTag & Incomplete)) {319 // 将完成的fiber的 effect list append到父级fiber上320 // 这样一级级递归上去后,根节点会有一条本次update所有有effect的fiber的list321 // 在执行DOM操作时只需要遍历这条链表而不需要再递归一遍整个fiber树就能执行effect对应DOM操作322 if (!returnFiber.firstEffect) {323 returnFiber.firstEffect = workInProgress.firstEffect;324 }325 if (workInProgress.lastEffect) {326 if (returnFiber.lastEffect) {327 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;...

Full Screen

Full Screen

FiberScheduler.js

Source:FiberScheduler.js Github

copy

Full Screen

...331 let current = workInProgress.alternate;332 let next = completeWork(current, workInProgress, nextRenderExpirationTime);333 let returnFiber = workInProgress.return;334 let siblingFiber = workInProgress.sibling;335 resetChildExpirationTime(workInProgress, nextRenderExpirationTime);336 if (next != null) {337 return next;338 }339 if (returnFiber != null) {340 if (returnFiber.firstEffect == null) {341 returnFiber.firstEffect = workInProgress.firstEffect;342 }343 if (workInProgress.lastEffect != null) {344 if (returnFiber.lastEffect != null) {345 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;346 }347 returnFiber.lastEffect = workInProgress.lastEffect;348 }349 let effectTag = workInProgress.effectTag;350 if (effectTag > PerformedWork) {351 if (returnFiber.lastEffect != null) {352 returnFiber.lastEffect.nextEffect = workInProgress;353 } else {354 returnFiber.firstEffect = workInProgress;355 }356 returnFiber.lastEffect = workInProgress;357 }358 }359 if (siblingFiber != null) {360 return siblingFiber;361 } else if (returnFiber != null) {362 workInProgress = returnFiber;363 continue;364 } else {365 const root = workInProgress.stateNode;366 root.isReadyForCommit = true;367 return null;368 }369 }370}371function commitRoot(finishedWork) {372 isWorking = true;373 isCommitting = true;374 let root = finishedWork.stateNode;375 root.isReadyForCommit = false;376 let firstEffect = null;377 if (finishedWork.effectTag > PerformedWork) {378 if (finishedWork.lastEffect != null) {379 finishedWork.lastEffect.nextEffect = finishedWork;380 firstEffect = finishedWork.firstEffect;381 } else {382 firstEffect = finishedWork;383 }384 } else {385 firstEffect = finishedWork.firstEffect;386 }387 nextEffect = firstEffect;388 while (nextEffect != null) {389 commitAllHostEffects();390 }391 root.current = finishedWork;392 isCommitting = false;393 isWorking = false;394 return root.current.expirationTime;395}396function commitAllHostEffects() {397 while (nextEffect != null) {398 let effectTag = nextEffect.effectTag;399 let primaryEffectTag = effectTag & ~PerformedWork;400 switch (primaryEffectTag) {401 case Placement: {402 commitPlacement(nextEffect);403 nextEffect.effectTag &= ~Placement;404 break;405 }406 case PlacementAndUpdate: {407 commitPlacement(nextEffect);408 nextEffect.effectTag &= ~Placement;409 commitWork(nextEffect);410 break;411 }412 case Update: {413 commitWork(nextEffect);414 break;415 }416 case Deletion: {417 commitDeletion(nextEffect);418 break;419 }420 }421 nextEffect = nextEffect.nextEffect;422 }423}424function computeAsyncExpiration(currentTime) {425 // Given the current clock time, returns an expiration time. We use rounding426 // to batch like updates together.427 // Should complete within ~1000ms. 1200ms max.428 const expirationMs = 5000;429 const bucketSizeMs = 250;430 return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs);431}432function computeInteractiveExpiration(currentTime) {433 // Should complete within ~500ms. 600ms max.434 const expirationMs = 500;435 const bucketSizeMs = 100;436 return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs);437}438export function recalculateCurrentTime() {439 mostRecentCurrentTime = msToExpirationTime(performance.now());440 return mostRecentCurrentTime;441}442export function computeExpirationForFiber(fiber) {443 let expirationTime;444 if (expirationContext !== NoWork) {445 // An explicit expiration context was set;446 expirationTime = expirationContext;447 } else if (isWorking) {448 if (isCommitting) {449 // Updates that occur during the commit phase should have sync priority450 // by default.451 expirationTime = Sync;452 } else {453 // Updates during the render phase should expire at the same time as454 // the work that is being rendered.455 expirationTime = nextRenderExpirationTime;456 }457 } else {458 // No explicit expiration context was set, and we're not currently459 // performing work. Calculate a new expiration time.460 if (fiber.mode & AsyncMode) {461 if (isBatchingInteractiveUpdates) {462 // This is an interactive update463 const currentTime = recalculateCurrentTime();464 expirationTime = computeInteractiveExpiration(currentTime);465 } else {466 // This is an async update467 const currentTime = recalculateCurrentTime();468 expirationTime = computeAsyncExpiration(currentTime);469 }470 } else {471 // This is a sync update472 expirationTime = Sync;473 }474 }475 if (isBatchingInteractiveUpdates) {476 // This is an interactive update. Keep track of the lowest pending477 // interactive expiration time. This allows us to synchronously flush478 // all interactive updates when needed.479 if (480 lowestPendingInteractiveExpirationTime === NoWork ||481 expirationTime > lowestPendingInteractiveExpirationTime482 ) {483 lowestPendingInteractiveExpirationTime = expirationTime;484 }485 }486 return expirationTime;487}488function resetChildExpirationTime(workInProgress, renderTime) {489 if (renderTime !== Never && workInProgress.expirationTime === Never) {490 // The children of this component are hidden. Don't bubble their491 // expiration times.492 return;493 }494 let newChildExpirationTime = NoWork;495 let child = workInProgress.child;496 while (child != null) {497 const childUpdateExpirationTime = child.expirationTime;498 const childChildExpirationTime = child.childExpirationTime;499 if (childUpdateExpirationTime > newChildExpirationTime) {500 newChildExpirationTime = childUpdateExpirationTime;501 }502 if (childChildExpirationTime > newChildExpirationTime) {...

Full Screen

Full Screen

ReactFiberScheduler.js

Source:ReactFiberScheduler.js Github

copy

Full Screen

...128 // We're out of completion phase so replaying is fine now.129 mayReplayFailedUnitOfWork = true;130 }131 stopWorkTimer(workInProgress);132 resetChildExpirationTime(workInProgress, nextRenderExpirationTime);133 if (__DEV__) {134 resetCurrentFiber();135 }136 if (nextUnitOfWork !== null) {137 // Completing this fiber spawned new work. Work on that next.138 return nextUnitOfWork;139 }140 if (141 returnFiber !== null &&142 // Do not append effects to parents if a sibling failed to complete143 (returnFiber.effectTag & Incomplete) === NoEffect144 ) {145 // Append all the effects of the subtree and this fiber onto the effect146 // list of the parent. The completion order of the children affects the...

Full Screen

Full Screen

simple_scheduler.js

Source:simple_scheduler.js Github

copy

Full Screen

...65 nextRenderExpirationTime,66 );67 }68 stopWorkTimer(workInProgress);69 resetChildExpirationTime(workInProgress, nextRenderExpirationTime);70 if (nextUnitOfWork !== null) {71 // Completing this fiber spawned new work. Work on that next.72 return nextUnitOfWork;73 }74 // 下面的两个if是构成effectlist的关键:从下往上挂载。75 // (1)把当前Fiber节点的子节点effect挂在到当前Fiber的父节点。当前Fiber相当于一个中间变量,沟通其父亲和其儿子。76 if (77 returnFiber !== null &&78 // Do not append effects to parents if a sibling failed to complete79 (returnFiber.effectTag & Incomplete) === NoEffect80 ) {81 // Append all the effects of the subtree and this fiber onto the effect82 // list of the parent. The completion order of the children affects the83 // side-effect order....

Full Screen

Full Screen

completeUnitOfWork.js

Source:completeUnitOfWork.js Github

copy

Full Screen

...17 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false);18 }19 stopWorkTimer(workInProgress);20 resetCurrentDebugFiberInDEV();21 resetChildExpirationTime(workInProgress);22 if (next !== null) {23 // Completing this fiber spawned new work. Work on that next.24 return next;25 }26 if (27 returnFiber !== null &&28 // Do not append effects to parents if a sibling failed to complete29 (returnFiber.effectTag & Incomplete) === NoEffect30 ) {31 // Append all the effects of the subtree and this fiber onto the effect32 // list of the parent. The completion order of the children affects the33 // side-effect order.34 if (returnFiber.firstEffect === null) {35 returnFiber.firstEffect = workInProgress.firstEffect;...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const elementHandle = await page.$('text=Playwright is a Node.js library to automate');7 await page.resetChildExpirationTime(elementHandle);8 await browser.close();9})();10const { chromium } = require('playwright');11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 const page = await context.newPage();15 const elementHandle = await page.$('text=Playwright is a Node.js library to automate');16 await page.resetChildExpirationTime(elementHandle, 10000);17 await browser.close();18})();19const { chromium } = require('playwright');20(async () => {21 const browser = await chromium.launch();22 const context = await browser.newContext();23 const page = await context.newPage();24 const elementHandle = await page.$('text=Playwright is a Node.js library to automate');25 await page.resetChildExpirationTime(elementHandle, 60000);26 await browser.close();27})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForTimeout(10000);7 await context.resetChildExpirationTime();8 await page.waitForTimeout(10000);9 await context.resetChildExpirationTime();10 await page.waitForTimeout(10000);11 await context.resetChildExpirationTime();12 await page.waitForTimeout(10000);13 await context.resetChildExpirationTime();14 await page.waitForTimeout(10000);15 await context.resetChildExpirationTime();16 await page.waitForTimeout(10000);17 await context.resetChildExpirationTime();18 await page.waitForTimeout(10000);19 await context.resetChildExpirationTime();20 await page.waitForTimeout(10000);21 await context.resetChildExpirationTime();22 await page.waitForTimeout(10000);23 await context.resetChildExpirationTime();24 await page.waitForTimeout(10000);25 await context.resetChildExpirationTime();26 await page.waitForTimeout(10000);27 await context.resetChildExpirationTime();28 await page.waitForTimeout(

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 resetChildExpirationTime(page);8 await page.waitForTimeout(1000 * 60 * 60 * 2);9 await page.screenshot({ path: `example.png` });10 await browser.close();11})();12const { chromium } = require('playwright');13(async () => {14 const browser = await chromium.launch();15 const context = await browser.newContext();16 const page = await context.newPage();17 await page.waitForTimeout(1000 * 60 * 60 * 2);18 await page.screenshot({ path: `example.png` });19 await browser.close();20})();21const { chromium } = require('playwright');22(async () => {23 const browser = await chromium.launch();24 const context = await browser.newContext();25 const page = await context.newPage();26 await page.waitForTimeout(1000 * 60 * 60 * 2);27 await page.screenshot({ path: `example.png` });28 await browser.close();29})();30const { chromium } = require('playwright');31(async () => {32 const browser = await chromium.launch();33 const context = await browser.newContext();34 const page = await context.newPage();35 await page.waitForTimeout(1000 * 60 * 60 * 2);36 await page.screenshot({ path: `example.png` });37 await browser.close();38})();39const { chromium } = require('playwright');40(async () => {41 const browser = await chromium.launch();42 const context = await browser.newContext();43 const page = await context.newPage();44 await page.waitForTimeout(1000 * 60 * 60 * 2);45 await page.screenshot({ path: `example.png` });

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.waitForTimeout(1000);7 await page.resetChildExpirationTime();8 await page.waitForTimeout(1000);9 await browser.close();10})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({4 });5 const page = await browser.newPage();6 await page.waitForTimeout(10000);7 await page.resetChildExpirationTime();8 await page.waitForTimeout(10000);9})();10const { chromium } = require('playwright');11(async () => {12 const browser = await chromium.launch({13 });14 const context = await browser.newContext();15 const page = await context.newPage();16 await page.waitForTimeout(10000);17 await browser.resetChildExpirationTime();18 await page.waitForTimeout(10000);19})();20const { chromium } = require('playwright');21(async () => {22 const browser = await chromium.launch({23 });24 const context = await browser.newContext();25 const page = await context.newPage();26 const frame = page.mainFrame();27 await page.goto('https

Full Screen

Using AI Code Generation

copy

Full Screen

1const playwright = require('playwright');2const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');3const browser = await playwright.chromium.launch();4const context = await browser.newContext();5const expirationTime = 60 * 1000;6resetChildExpirationTime(context, expirationTime);7const page = await context.newPage();8await browser.close();9const playwright = require('playwright');10const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');11const browser = await playwright.chromium.launch();12const context = await browser.newContext();13const expirationTime = 60 * 1000;14resetChildExpirationTime(context, expirationTime);15const page = await context.newPage();16await browser.close();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resetChildExpirationTime } = require('playwright-core/lib/server/browserContext');2const { chromium } = require('playwright-core');3const { chromium } = require('playwright-core');4(async () => {5 const browser = await chromium.launch({ headless: false });6 const context = await browser.newContext();7 await context.newPage();8 await context.newPage();9 await context.newPage();10 await context.newPage();11 resetChildExpirationTime(context);12 await browser.close();13})();14const { resetChildExpirationTime } = require('playwright-core/lib/server/browserContext');15const { chromium } = require('playwright-core');16const { chromium } = require('playwright-core');17(async () => {18 const browser = await chromium.launch({ headless: false });19 const context = await browser.newContext();20 await context.newPage();21 await context.newPage();22 await context.newPage();23 await context.newPage();24 resetChildExpirationTime(context);25 await browser.close();26})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resetChildExpirationTime } = require('@playwright/test/lib/runner/Test');2resetChildExpirationTime();3const { setChildExpirationTime } = require('@playwright/test/lib/runner/Test');4setChildExpirationTime(1000);5const { setTestTimeout } = require('@playwright/test/lib/runner/Test');6setTestTimeout(1000);7const { setTestName } = require('@playwright/test/lib/runner/Test');8setTestName('testName');9const { setWorkerIndex } = require('@playwright/test/lib/runner/Test');10setWorkerIndex(1);11const { setWorkerOrdinal } = require('@playwright/test/lib/runner/Test');12setWorkerOrdinal(2);13const { setWorkerFixtureValue } = require('@playwright/test/lib/runner/Test');14setWorkerFixtureValue('key', 'value');15const { setConfig } = require('@playwright/test/lib/runner/Test');16setConfig('key', 'value');17const { setFixtures } = require('@playwright/test/lib/runner/Test');18setFixtures({});19const { setTestType } = require('@playwright/test/lib/runner/Test');20setTestType('testType');21const { setTestInfo } = require('@playwright/test/lib/runner/Test');

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');2resetChildExpirationTime(browserContext, timeout);3const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');4resetChildExpirationTime(browserContext, timeout);5 ✓ test (2s)6 1 passed (2s)7const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');8resetChildExpirationTime(browserContext, 0);9 1 failed (2s)10 at Object.<anonymous> (test.js:4:3)11const { resetChildExpirationTime } = require('playwright/lib/server/browserContext');12resetChildExpirationTime(browserContext, 1);13 1 failed (2s)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { resetChildExpirationTime } = require('playwright/lib/utils/registry');2resetChildExpirationTime(300000);3const playwright = require('playwright');4(async () => {5 for (const browserType of BROWSER) {6 const browser = await playwright[browserType].launch();7 const context = await browser.newContext();8 const page = await context.newPage();9 await page.screenshot({ path: `${browserType}.png` });10 await browser.close();11 }12})();13const { resetChildExpirationTime } = require('playwright/lib/utils/registry');14resetChildExpirationTime(300000);15const playwright = require('playwright');16(async () => {17 for (const browserType of BROWSER) {18 const browser = await playwright[browserType].launch();19 const context = await browser.newContext();20 const page = await context.newPage();21 await page.screenshot({ path: `${browserType}.png` });22 await browser.close();23 }24})();25const { resetChildExpirationTime } = require('playwright/lib/utils/registry');26resetChildExpirationTime(300000);27const playwright = require('playwright');28(async () => {29 for (const browserType of BROWSER) {30 const browser = await playwright[browserType].launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 await page.screenshot({ path: `${browserType}.png` });34 await browser.close();35 }36})();37const { resetChildExpirationTime } = require('playwright/lib/utils/registry');

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

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

Run Playwright Internal automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful