import { getCurrentEventPriority , scheduleMicrotask , } from './ReactFiberHostConfig' ; import { DefaultEventPriority , DiscreteEventPriority , getCurrentUpdatePriority , lanesToEventPriority , setCurrentUpdatePriority , } from './ReactEventPriorities' ; import { createWorkInProgress } from './ReactFiber' ; import { beginWork } from './ReactFiberBeginWork' ; import { commitBeforeMutationEffects , commitLayoutEffects , commitMutationEffects , commitPassiveMountEffects , commitPassiveUnmountEffects , } from './ReactFiberCommitWork' ; import { completeWork } from './ReactFiberCompleteWork' ; import { MutationMask , NoFlags , PassiveMask } from './ReactFiberFlags' ; import { getHighestPriorityLane , getNextLanes , includesSomeLane , Lane , Lanes , markRootFinished , markRootUpdated , markStarvedLanesAsExpired , mergeLanes , NoLane , NoLanes , NoTimestamp , shouldTimeSlice , SyncLane , } from './ReactFiberLane' ; import { flushSyncCallbacks , scheduleLegacySyncCallback , scheduleSyncCallback , } from './ReactFiberSyncTaskQueue' ; import { Fiber , FiberRoot } from './ReactInternalTypes' ; import { LegacyRoot } from './ReactRootTags' ; import { ConcurrentMode , NoMode } from './ReactTypeOfMode' ; import { HostRoot } from './ReactWorkTags' ; import { cancelCallback , now , shouldYield } from './Scheduler' ; import { scheduleCallback , NormalPriority as NormalSchedulerPriority , } from './Scheduler' ; import { enqueueInterleavedUpdates } from './ReactFiberInterleavedUpdates' ; type ExecutionContext = number ; export const NoContext = 0b000000 ; const BatchedContext = 0b000001 ; const EventContext = 0b000010 ; const LegacyUnbatchedContext = 0b000100 ; const RenderContext = 0b001000 ; const CommitContext = 0b010000 ; type RootExitStatus = 5 | 0 ; const RootIncomplete = 0 ; const RootCompleted = 5 ; let executionContext = NoContext ; /**
 * 当前在构建应用的root
 */ let workInProgressRoot = null ; /**
 * 当前正在进行工作的fiber节点
 */ let workInProgress = null ; /**
 * 当前渲染中的Lanes
 */ let workInProgressRootRenderLanes = NoLanes ; let currentEventTime = NoTimestamp ; let rootDoesHavePassiveEffects = false ; /**
 * 当前包含PassiveEffect(useEffect产生的effect)的FiberRoot
 */ let rootWithPendingPassiveEffects = null ; export let subtreeRenderLanes = NoLanes ; const completeUnitOfWork = ( unitOfWork ) : void => { let completedWork = unitOfWork ; do { const current = completedWork . alternate ; const returnFiber = completedWork . return ; let next = completeWork ( current , completedWork ) ; const siblingFiber = completedWork . sibling ; if ( siblingFiber !== null ) { workInProgress = siblingFiber ; return ; } completedWork = returnFiber ; workInProgress = completedWork ; } while ( completedWork !== null ) ; } ; param unitOfWork const performUnitOfWork = ( unitOfWork ) : void => { const current = unitOfWork . alternate ; let next = null ; next = beginWork ( current , unitOfWork , subtreeRenderLanes ) ; unitOfWork . memoizedProps = unitOfWork . pendingProps ; if ( next === null ) { completeUnitOfWork ( unitOfWork ) ; } else { workInProgress = next ; } } ; param root const prepareFreshStack = ( root , lanes ) => { root . finishedWork = null ; workInProgressRoot = root ; workInProgress = createWorkInProgress ( root . current , null ) ; workInProgressRootRenderLanes = subtreeRenderLanes = lanes ; enqueueInterleavedUpdates ( ) ; } ; returns const flushPassiveEffectsImpl = ( ) => { if ( rootWithPendingPassiveEffects === null ) return false ; const root = rootWithPendingPassiveEffects ; rootWithPendingPassiveEffects = null ; const prevExecutionContext = executionContext ; executionContext |= CommitContext ; commitPassiveUnmountEffects ( root . current ) ; commitPassiveMountEffects ( root , root . current ) ; executionContext = prevExecutionContext ; flushSyncCallbacks ( ) ; return true ; } ; returns export const flushPassiveEffects = ( ) : boolean => { if ( rootWithPendingPassiveEffects !== null ) { try { return flushPassiveEffectsImpl ( ) ; } finally { } } return false ; } ; const renderRootSync = ( root , lanes ) => { const prevExecutionContext = executionContext ; executionContext |= RenderContext ; if ( workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes ) { prepareFreshStack ( root , lanes ) ; } while ( workInProgress !== null ) { performUnitOfWork ( workInProgress ) ; } executionContext = prevExecutionContext ; /**
     * 把它设置为null表示当前没有进行中的render
     */ workInProgressRoot = null ; workInProgressRootRenderLanes = NoLanes ; } ; const commitRootImpl = ( root ) : null => { do { flushPassiveEffects ( ) ; } while ( rootWithPendingPassiveEffects !== null ) ; const finishedWork = root . finishedWork ; if ( finishedWork === null ) return null ; root . finishedWork = null ; /**
     * CommitRoot不会返回连续的操作,他总是同步的完成,所以我们可以清除他们
     * 以允许新的callback能被规划
     */ root . callbackNode = null ; root . callbackPriority = NoLane ; /**
     * 剩余需要工作的lanes为HostRoot的lanes和他子树lanes的并集,finishedWork为HostRoot一般不会拥有剩余lanes
     * 但是他的childLanes有剩余还是挺常见的，比如一个子树高优先级任务打断了一个低优先级的任务
     * 那个低优先级任务的lanes就会保存到现在，就可以从HostRoot的childLanes获取到
     * 具体可以看completeWork中的bubbleProperties，他将子树中跳过更新的lanes冒泡到上级节点
     * 的childLanes中
     */ let remainingLanes = mergeLanes ( finishedWork . lanes , finishedWork . childLanes ) ; markRootFinished ( root , remainingLanes ) ; workInProgressRoot = null ; workInProgress = null ; if ( ( finishedWork . subtreeFlags & PassiveMask ) !== NoFlags || ( finishedWork . flags & PassiveMask ) !== NoFlags ) { if ( ! rootDoesHavePassiveEffects ) { rootDoesHavePassiveEffects = true ; scheduleCallback ( NormalSchedulerPriority , ( ) => { flushPassiveEffects ( ) ; return null ; } , null ) ; } } /**
     * 判断是否需要进行工作，大概率是需要进行dom操作，不过也不一定
     * 比如使用了useLayoutEffect的函数组件会被打上Update的标签
     * 但他不一定会进行dom操作
     */ const subtreeHasEffects = ( finishedWork . subtreeFlags & MutationMask ) !== NoFlags ; const rootHasEffect = ( finishedWork . flags & MutationMask ) !== NoFlags ; if ( rootHasEffect || subtreeHasEffects ) { commitBeforeMutationEffects ( root , finishedWork ) ; commitMutationEffects ( root , finishedWork ) ; root . current = finishedWork ; commitLayoutEffects ( finishedWork , root ) ; } else { root . current = finishedWork ; } const rootDidHavePassiveEffects = rootDoesHavePassiveEffects ; if ( rootDidHavePassiveEffects ) { rootDoesHavePassiveEffects = false ; rootWithPendingPassiveEffects = root ; } ensureRootIsScheduled ( root , now ( ) ) ; return null ; } ; const commitRoot = ( root ) : null => { commitRootImpl ( root ) ; return null ; } ; param root export const performSyncWorkOnRoot = ( root ) => { const lanes = getNextLanes ( root , NoLanes ) ; if ( ! includesSomeLane ( lanes , SyncLane ) ) return null ; const exitStatus = renderRootSync ( root , lanes ) ; const finishedWork = root . current . alternate ; root . finishedWork = finishedWork ; commitRoot ( root ) ; return null ; } ; param root param currentTime returns const ensureRootIsScheduled = ( root , currentTime ) => { const existingCallbackNode = root . callbackNode ; /**
     * 检查是否某些lane上的任务已经过期了如果过期了把他们标记为过期，
     * 然后接下来就能进行他们的工作
     */ markStarvedLanesAsExpired ( root , currentTime ) ; const nextLanes = getNextLanes ( root , root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes ) ; if ( nextLanes === NoLanes ) { if ( existingCallbackNode !== null ) { throw new Error ( 'Not Implement' ) ; } root . callbackNode = null ; root . callbackPriority = NoLane ; return ; } /**
     * 我们取最高的lane去代表该callback的优先级
     */ const newCallbackPriority = getHighestPriorityLane ( nextLanes ) ; const existingCallbackPriority = root . callbackPriority ; /**
     * 检查是是否已经存在任务，如果存在且优先级相同就可以复用他
     * 这就是一个click事件内的多次setState
     * 导致多次scheduleUpdateOnFiber但也只会渲染一次的原因
     * 同一优先级的update只会被调度一次，后续的update会直接返回
     * 只需要把他们挂在pending queue上的就行，待会beginWork阶段中拥有相同优先级的
     * update会被一同reduce了
     */ if ( existingCallbackPriority === newCallbackPriority ) { return ; } if ( existingCallbackNode !== null ) { cancelCallback ( existingCallbackNode as any ) ; } let newCallbackNode ; if ( newCallbackPriority === SyncLane ) { if ( root . tag === LegacyRoot ) { scheduleLegacySyncCallback ( performSyncWorkOnRoot . bind ( null , root ) ) ; } else { scheduleSyncCallback ( performSyncWorkOnRoot . bind ( null , root ) ) ; } scheduleMicrotask ( flushSyncCallbacks ) ; newCallbackNode = null ; } else { let schedulerPriorityLevel ; switch ( lanesToEventPriority ( nextLanes ) ) { case DefaultEventPriority : schedulerPriorityLevel = NormalSchedulerPriority ; break ; default : throw new Error ( 'Not implement' ) ; } newCallbackNode = scheduleCallback ( schedulerPriorityLevel , performConcurrentWorkOnRoot . bind ( null , root ) , null ) ; } root . callbackNode = newCallbackNode ; root . callbackPriority = newCallbackPriority ; } ; const performConcurrentWorkOnRoot = ( root , didTimeout ) : null | Function => { currentEventTime = NoTimestamp ; const originalCallbackNode = root . callbackNode ; const didFlushPassiveEffects = flushPassiveEffects ( ) ; if ( didFlushPassiveEffects ) { throw new Error ( 'Not Implement' ) ; } const lanes = getNextLanes ( root , root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes ) ; if ( lanes === NoLanes ) { return null ; } const exitStatus = shouldTimeSlice ( root , lanes ) && ! didTimeout ? renderRootConcurrent ( root , lanes ) : renderRootSync ( root , lanes ) ; /**
     * 在时间切片的过程中，如果还有任务剩余，就会返回RootIncomplete
     */ if ( exitStatus !== RootIncomplete ) { const finishedWork = root . current . alternate as any ; root . finishedWork = finishedWork ; finishConcurrentRender ( root , 5 , lanes ) ; } ensureRootIsScheduled ( root , now ( ) ) ; if ( root . callbackNode === originalCallbackNode ) { return performConcurrentWorkOnRoot . bind ( null , root ) ; } return null ; } ; param root param exitStatus param lanes const finishConcurrentRender = ( root , exitStatus , lanes ) : void => { switch ( exitStatus ) { case RootCompleted : commitRoot ( root ) ; break ; default : throw new Error ( 'Not Implement' ) ; } } ; /**
 * 在这个切片中一fiber为最小工作单位进行render工作，
 * 这个切片到期就把控制权交还给浏览器
 */ const workLoopConcurrent = ( ) => { while ( workInProgress !== null && ! shouldYield ( ) ) { performUnitOfWork ( workInProgress ) ; } } ; param root param lanes returns const renderRootConcurrent = ( root , lanes ) => { const prevExecutionContext = executionContext ; executionContext |= RenderContext ; if ( workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes ) { prepareFreshStack ( root , lanes ) ; } do { workLoopConcurrent ( ) ; break ; } while ( true ) ; executionContext = prevExecutionContext ; if ( workInProgress !== null ) { return RootIncomplete ; } else { workInProgressRoot = null ; workInProgressRootRenderLanes = NoLanes ; return RootCompleted ; } } ; param sourceFiber param lane returns const markUpdateLaneFromFiberToRoot = ( sourceFiber , lane ) : FiberRoot | null => { sourceFiber . lanes = mergeLanes ( sourceFiber . lanes , lane ) ; let alternate = sourceFiber . alternate ; if ( alternate !== null ) { alternate . lanes = mergeLanes ( alternate . lanes , lane ) ; } let node = sourceFiber ; let parent = sourceFiber . return ; while ( parent !== null ) { parent . childLanes = mergeLanes ( parent . childLanes , lane ) ; alternate = parent . alternate ; if ( alternate !== null ) { alternate . childLanes = mergeLanes ( alternate . childLanes , lane ) ; } node = parent ; parent = node . return ; } if ( node . tag === HostRoot ) { const root = node . stateNode ; return root ; } else { return null ; } } ; returns export const requestEventTime = ( ) => { if ( ( executionContext & ( RenderContext | CommitContext ) ) !== NoContext ) { throw new Error ( 'Not Implement' ) ; } if ( currentEventTime !== NoTimestamp ) { return currentEventTime ; } currentEventTime = now ( ) ; return currentEventTime ; } ; param fiber returns export const scheduleUpdateOnFiber = ( fiber , lane , eventTime ) : FiberRoot | null => { const root = markUpdateLaneFromFiberToRoot ( fiber , lane ) ; if ( root === null ) { return null ; } markRootUpdated ( root , lane , eventTime ) ; if ( root === workInProgressRoot ) { } if ( lane === SyncLane ) { if ( ( executionContext & LegacyUnbatchedContext ) !== NoContext && ( executionContext & ( RenderContext | CommitContext ) ) === NoContext ) { performSyncWorkOnRoot ( root ) ; } else { ensureRootIsScheduled ( root , eventTime ) ; if ( executionContext === NoContext && ( fiber . mode & ConcurrentMode ) === NoMode ) { throw new Error ( 'Not Implement' ) ; } } } else { ensureRootIsScheduled ( root , eventTime ) ; } return root ; } ; param fn param a param b param c param d returns export const discreteUpdates = < A , B , C , D , R > ( fn , a , b , c , d ) : R => { const previousPriority = getCurrentUpdatePriority ( ) ; try { setCurrentUpdatePriority ( DiscreteEventPriority ) ; return fn ( a , b , c , d ) ; } finally { setCurrentUpdatePriority ( previousPriority ) ; } } ; param fn param a returns export const batchedEventUpdates = < A , R > ( fn , a ) : R => { const prevExecutionContext = executionContext ; executionContext |= EventContext ; try { return fn ( a ) ; } finally { executionContext = prevExecutionContext ; } } ; param fn param a returns export const unbatchedUpdates = < A , R > ( fn , a ) : R => { const prevExecutionContext = executionContext ; executionContext &= ~ BatchedContext ; executionContext |= LegacyUnbatchedContext ; try { return fn ( a ) ; } finally { executionContext = prevExecutionContext ; } } ; param fiber returns export const requestUpdateLane = ( fiber ) : Lane => { const mode = fiber . mode ; if ( ( mode & ConcurrentMode ) === NoMode ) return SyncLane ; else if ( ( executionContext & RenderContext ) !== NoContext ) { throw new Error ( 'Not Implement' ) ; } /**
     * 不同模块产生的优先级能互动的桥梁比如ReactDom中产生的一个click事件就会先将
     * CurrentUpdatePriority设置为DiscreteEventPriority然后像reconciler这种模块就能在这里获取到
     * 当前的UpdatePriority
     */ const updateLane = getCurrentUpdatePriority ( ) ; if ( updateLane !== NoLane ) { return updateLane ; } const eventLane = getCurrentEventPriority ( ) ; return eventLane ; } ; export const isInterleavedUpdate = ( fiber , lane ) : boolean => { return workInProgressRoot !== null && ( fiber . mode & ConcurrentMode ) !== NoMode ; } ;