「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」
在前面的文章提到了scheduleUpdateOnFiber函数会调用 ensureRootIsScheduled , 显然后者包含了与渲染更新有关的重要逻辑,今天来分析一下这个函数做了哪些东西。
功能
这是用于为一个 root 调度一个任务,每个 root 只能有一个任务。如果任务已经被调度完成,则会进行一个 check, 以确保处于 existing 状态的任务的优先级与 root 的下一层的优先级相同。此函数会在每次更新时被调用,退出调用之前会给 root.callback 和 root.callbackPriority 重新赋值。
车道与优先级
从ensureRootIsScheduled的代码可以意识到,我们上一篇文章提到的“车道”(lane)概念,其实是用于实现一种优先级机制。
const newCallbackPriority = getHighestPriorityLane(nextLanes)
每一个车道都表示一个优先级。这里截一张图,看一下各个车道具体的取值如何:
每一个车道在二进制第 i 位上为 1,表示优先级为 i,i 越小,优先级越高。如果有多个二进制位是1,表示一组车道,有多个优先级。
为什么认为 i 越小,优先级越高?
export function getHighestPriorityLane (lanes: Lanes): Lane {
return lanes & -lanes
}
getHighestPriorityLane 从名字上看就知道它是获取最高优先级的 lane 的,而 lanes & -lanes 的作用是返回一个数,最低非 0 位保留为 1,其它位设为 0。举个例子,0b110 & -0b110 的结果为 2,即 0b010。
这里可以多提一句,我们又是怎么看出 lanes & -lanes的运算结果是这样呢?培训过 acm 的人想必很敏感了,这是因为在计算机中一个负数是用补码表示的,补码等于反码加 1,这个结果又可以看成从最高位开始往低位扫描,直到遇到最低非 0 位,按位取反。因此一个数与它的负数做位与运算,结果自然是保留最低非0位,其它位为 0 了。
实现逻辑
- 调用
markStarvedLanesAsExpired(root, currentTime),用于将已经被其他工作“饿死”的lane标记为已过期,后面会避免使用已过期的 lane - 调用
getNextLanes方法获取下一次要用的车道组,如果获取不到可用车道,即调用结果是NoLanes, 则退出。退出前执行root.callbackNode = null和root.callbackPriority = NoLane - 如果当前调度的任务是是一个 Scheduler 任务而不是一个“act”任务,则退出,重新调度“act”的队列
- 如果是开发模式或
ReactCurrentActQueue.current为 null 或root.callbackNode是 fakeActCallbackNode,则退出 root.callbackNode如果存在,则执行cancelCallback (root.callbackNode)- 如果车道组中的最高优先级车道是
SyncLane,则调用scheduleLegacySyncCallback(performSyncWorkOnRoot.bind(null, root))或scheduleSyncCallback(performSyncWorkOnRoot.bind(null, root)),调用哪个取决于root.tag - 如果支持微任务,则执行
scheduleMicrotask(flushSyncCallbacks),否则执行scheduleCallback(ImmediateSchedulerPriority, flushSyncCallbacks) - root.callbackNode 置 null
- 如果 6 不成立,则调lanesToEventPriority(nextLanes),根据返回情况给临时变量
schedulerPriorityLevel分配不同的取值,然后执行以下代码
root.callbackNode = scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root),
)
下节预告
上一节里我们又看到一些新的名词,markStarvedLanesAsExpired、cancelCallback、scheduleCallback、scheduleSyncCallback、scheduleMicrotask等,这些重要的概念将在下一次更文中讲解。