// requestWork is called by the scheduler whenever a root receives an update.
// It's up to the renderer to call renderRoot at some point in the future.
function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {
// 把当前 root设置为最高优先级
addRootToSchedule(root, expirationTime);
if (isRendering) {
// 在render过程当中, 此时直接return
// Prevent reentrancy. Remaining work will be scheduled at the end of
// the currently rendering batch.
return;
}
// 批量处理相关
// 调用 setState 时在 enqueueUpdates 前 batchedUpdates 会把 isBatchingUpdates 设置成 true
if (isBatchingUpdates) {
// Flush work at the end of the batch.
if (isUnbatchingUpdates) {
// ...unless we're inside unbatchedUpdates, in which case we should
// flush it now.
nextFlushedRoot = root;
nextFlushedExpirationTime = Sync;
performWorkOnRoot(root, Sync, false);
}
return;
}
// TODO: Get rid of Sync and use current time?
if (expirationTime === Sync) {
// 同步的调用 js 代码
performSyncWork();
} else {
// 异步调度 独立的 react 模块包,利用浏览器有空闲的时候进行执行,设置 deadline 在此之前执行
scheduleCallbackWithExpirationTime(root, expirationTime);
}
}
首先调用了addRootToSchedule:
/**
* 将 root 加入到调度队列
*
* @param {FiberRoot} root
* @param {ExpirationTime} expirationTime
*/
function addRootToSchedule(root: FiberRoot, expirationTime: ExpirationTime) {
// Add the root to the schedule.
// Check if this root is already part of the schedule.
// root.nextScheduledRoot 用来判断是否有异步任务正在调度, 为 null 时会增加 nextScheduledRoot
// 这个 root 还没有进入过调度
if (root.nextScheduledRoot === null) {
// This root is not already scheduled. Add it.
root.expirationTime = expirationTime;
if (lastScheduledRoot === null) {
// lastScheduledRoot firstScheduledRoot 是单向链表结构,表示多个 root 更新
// 这里只有一个 root 只会在这里执行
firstScheduledRoot = lastScheduledRoot = root;
root.nextScheduledRoot = root;
} else {
// 有个多个root 时进行单向链表的插入操作
lastScheduledRoot.nextScheduledRoot = root;
lastScheduledRoot = root;
lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
}
} else {
// This root is already scheduled, but its priority may have increased.
// 传入的 root 已经进入过调度, 把 root 的优先级设置最高
const remainingExpirationTime = root.expirationTime;
// 如果 root 的 expirationTime 是同步或者优先级低,增加为计算出的最高优先级
if (expirationTime > remainingExpirationTime) {
// Update the priority.
// 把当前 root 的优先级设置为当前优先级最高的
root.expirationTime = expirationTime;
}
}
}
requestWork
首先说明以下
requestWork
的核心功能:root
节点加入到root
调度队列中expirationTime
的类型判断调度的类型下面,我们来详细分析下
requestWork
的流程。首先来看requestWork
:首先调用了
addRootToSchedule
:作用比较清晰:
root
是否调度过, 单个或多个root
构建成单向链表结构回到
requestWork
,分成了三个分支:我们来分别解释一下:
isRendering
顾名思义在render
过程当中, 此时直接返回return
。batchedUpdate
批处理的时候,将isRendering
置成true
,这样每次在执行setState
时,都会走isRendering
的分支直接返回,阻止更新,相当于暂停住,当第二个setState
时依旧直接返回,避免出现频繁式的更新,也就是批处理。isBatchingUpdates
中又有一个isUnbatchingUpdates
分支。isUnbatchingUpdates
会在执行unbatchedUpdates()
时设置为true
。 也就是在首次渲染的时候不需要进行批处理,所以就会进行立即更新。 这里的两个变量名可能会造成误解,isBatchingUpdates
和isUnbatchingUpdates
这两个变量并不是互斥的,而是在两个方法中设置的哨兵变量。如果是批处理的过程中的话,也会直接
return
。当前面的
expirationTime
被设置成了同步任务的时候,就会立即执行。 剩余的则会进入scheduleCallbackWithExpirationTime
通过ExpirationTime
进行调度。