import { ImmediatePriority , NormalPriority , PriorityLevel , } from './SchedulerPriorities' ; import { push , Node , peek , pop } from './SchedulerMinHeap' ; type Task = { id : number ; /**
     * 该任务的要执行的操作，最常见的就是performConcurrentWorkOnRoot
     * 时间分片就靠此实现
     */ callback : Function | null ; /**
     * 该任务的优先级
     */ priorityLevel : PriorityLevel ; /**
     * 该任务的开始时间
     */ startTime : number ; /**
     * 该任务的过期时间
     */ expirationTime : number ; /**
     * 最小优先队列中会按照该字段将一个节点放到队列合适的位置和expirationTime是同一个值
     */ sortIndex : number ; } ; const getCurrentTime = ( ) => performance . now ( ) ; /**
 * NORMAL级别任务过期时间的计算标准，比如现在时间为0，
 * 有一个Normal级别的任务被调度了，那么他的过期时间就为
 * `当前时间 +NORMAL_PRIORITY_TIMEOUT`
 * 等于5000
 */ const NORMAL_PRIORITY_TIMEOUT = 5000 ; /**
 * IMMEDIATE级别任务过期时间计算标准，和上面同理
 */ const IMMEDIATE_PRIORITY_TIMEOUT = - 1 ; let taskIdCounter = 1 ; /**
 * 延时任务队列，我们的代码中没有用到
 */ const timerQueue = [ ] ; /**
 * 存放任务的最小有限队列
 */ const taskQueue = [ ] ; let isHostCallbackScheduled = false ; let isHostTimeoutScheduled = false ; let currentPriorityLevel = NormalPriority ; let currentTask = null ; let scheduledHostCallback = null ; let isPerformingWork = false ; let isMessageLoopRunning = false ; let dealine = 0 ; let yieldInterval = 5 ; let needsPaint = false ; let taskTimeoutID = - 1 ; const performWorkUntilDeadline = ( ) => { if ( scheduledHostCallback !== null ) { const currentTime = getCurrentTime ( ) ; dealine = currentTime + yieldInterval ; const hasTimeRemaining = true ; let hasMoreWork = true ; try { /**
             * 在我们的代码中scheduledHostCallback一直都是flushWork
             * 下面这行代码执行了flushWork
             */ hasMoreWork = scheduledHostCallback ( hasTimeRemaining , currentTime ) ; } finally { if ( hasMoreWork ) { /**
                 * 如果任务队列还不为空，就注册一个宏任务待会回来继续执行任务
                 * 时间分片实现的关键
                 */ schedulePerformWorkUntilDeadline ( ) ; } else { isMessageLoopRunning = false ; scheduledHostCallback = null ; } } } else { isMessageLoopRunning = false ; } needsPaint = false ; } ; param callback const requestHostCallback = ( callback ) : void => { scheduledHostCallback = callback ; if ( ! isMessageLoopRunning ) { isMessageLoopRunning = true ; schedulePerformWorkUntilDeadline ( ) ; } } ; let schedulePerformWorkUntilDeadline ; { const channel = new MessageChannel ( ) ; const port = channel . port2 ; channel . port1 . onmessage = performWorkUntilDeadline ; schedulePerformWorkUntilDeadline = ( ) => { port . postMessage ( null ) ; } ; } param currentTime const advanceTimers = ( currentTime ) => { let timer = peek ( timerQueue ) as Task ; while ( timer !== null ) { if ( timer . callback === null ) { pop ( timerQueue ) ; } else if ( timer . startTime <= currentTime ) { pop ( timerQueue ) ; timer . sortIndex = timer . expirationTime ; push ( taskQueue , timer ) ; } else { return ; } timer = peek ( timerQueue ) as any ; } } ; returns const shouldYieldToHost = ( ) : boolean => { return getCurrentTime ( ) >= dealine ; } ; const requestHostTimeout = ( callback , ms ) : void => { taskTimeoutID = setTimeout ( ( ) => { callback ( getCurrentTime ( ) ) ; } , ms ) as unknown as number ; } ; const handleTimeout = ( currentTime ) => { isHostTimeoutScheduled = false ; advanceTimers ( currentTime ) ; if ( ! isHostCallbackScheduled ) { if ( peek ( taskQueue ) !== null ) { isHostCallbackScheduled = true ; requestHostCallback ( flushWork ) ; } else { const firstTimer = peek ( timerQueue ) as Task ; if ( firstTimer !== null ) { requestHostTimeout ( handleTimeout , firstTimer . startTime - currentTime ) ; } } } } ; const workLoop = ( hasTimeRemaining , initialTime ) => { let currentTime = initialTime ; advanceTimers ( currentTime ) ; currentTask = peek ( taskQueue ) as any ; while ( currentTask !== null ) { if ( currentTask . expirationTime > currentTime && ( ! hasTimeRemaining || shouldYieldToHost ( ) ) ) { break ; } const callback = currentTask . callback ; if ( typeof callback === 'function' ) { currentTask . callback = null ; currentPriorityLevel = currentTask . priorityLevel ; const didUserCallbackTimeout = currentTask . expirationTime <= currentTime ; const continuationCallback = callback ( didUserCallbackTimeout ) ; currentTime = getCurrentTime ( ) ; if ( typeof continuationCallback === 'function' ) { currentTask . callback = continuationCallback ; } else { if ( currentTask === peek ( taskQueue ) ) { pop ( taskQueue ) ; } } advanceTimers ( currentTime ) ; } else { pop ( taskQueue ) ; } currentTask = peek ( taskQueue ) as any ; } if ( currentTask !== null ) { return true ; } else { const firstTimer = peek ( timerQueue ) as Task ; if ( firstTimer !== null ) { requestHostTimeout ( handleTimeout , firstTimer . startTime - currentTime ) ; } return false ; } } ; const flushWork = ( hasTimeRemaining , initialTime ) => { isHostCallbackScheduled = false ; if ( isHostTimeoutScheduled ) { throw new Error ( 'Not Implement' ) ; } isPerformingWork = true ; const previousPriorityLevel = currentPriorityLevel ; try { return workLoop ( hasTimeRemaining , initialTime ) ; } finally { currentTask = null ; currentPriorityLevel = previousPriorityLevel ; isPerformingWork = false ; } } ; param priorityLevel param callback param options returns const unstable_scheduleCallback = ( priorityLevel , callback , options ) : Task => { const currentTime = getCurrentTime ( ) ; let startTime ; if ( typeof options === 'object' && options !== null ) { const delay = options . delay ; if ( typeof delay === 'number' && delay > 0 ) { startTime = currentTime + delay ; } else { startTime = currentTime ; } } else { startTime = currentTime ; } let timeout ; switch ( priorityLevel ) { case ImmediatePriority : timeout = IMMEDIATE_PRIORITY_TIMEOUT ; break ; case NormalPriority : timeout = NORMAL_PRIORITY_TIMEOUT ; break ; default : throw new Error ( 'Not Implement' ) ; } const expirationTime = startTime + timeout ; const newTask = { id : taskIdCounter ++ , callback , priorityLevel , startTime , expirationTime , sortIndex : - 1 , } ; if ( startTime > currentTime ) { throw new Error ( 'Not Implement' ) ; } else { newTask . sortIndex = expirationTime ; push ( taskQueue , newTask ) ; if ( ! isHostCallbackScheduled && ! isPerformingWork ) { isHostCallbackScheduled = true ; requestHostCallback ( flushWork ) ; } } return newTask ; } ; param task const unstable_cancelCallback = ( task ) => { /**
     * 要删除一个优先队列中的随机元素，需要O(N)的时间复杂度很不划算
     * 不如直接把他的callback直接赋值为null然后在pop出来的时候在判断一下
     * 是否因该忽略他就行
     */ task . callback = null ; } ; export { NormalPriority as unstable_NormalPriority , ImmediatePriority as unstable_ImmediatePriority , getCurrentTime as unstable_now , unstable_scheduleCallback , shouldYieldToHost as unstable_shouldYield , unstable_cancelCallback , } ;