集群注册的公司可以做网站备案,怎么编写一个网站,好的手机端网站模板下载,东莞住房与城乡建设网站performWork 1 #xff09;概述
performWork 涉及到在调度完成#xff0c;或者同步任务进来之后整个 root 节点链条如何更新怎么更新一棵 Fiber 树#xff0c;它的每一个节点是如何被遍历到#xff0c;以及如何进行更新操作A. 在执行 performWork 时候#xff0c;是否有 …performWork 1 概述
performWork 涉及到在调度完成或者同步任务进来之后整个 root 节点链条如何更新怎么更新一棵 Fiber 树它的每一个节点是如何被遍历到以及如何进行更新操作A. 在执行 performWork 时候是否有 deadline 的区分 deadline 是通过 reactschedule 它的一个时间片更新的过程当中产生的一个叫做 deadlineobject 的对象它可以用来判断我们在一帧的渲染时间内留给react进行fiber树渲染的时间还有没有 B.循环渲染root的条件 一个应用当中可能会有多个root节点同时每一个root节点上面呢又会有不同优先级的任务产生要循环去遍历各个不同的root节点以及他们的不同的优先级的任务然后按照优先级去一个个去更新这个循环它如何建立如何判断这个循环是否成立的条件 C.超过时间片之后的一个处理 在deadline到了之后就是我们这一帧的渲染时间已经到了我们需要把js的执行权又交回给浏览器这个时候又该怎么做
2 源码
定位到 packages/react-reconciler/src/ReactFiberScheduler.js
function performAsyncWork() {try {if (!shouldYieldToRenderer()) {// The callback timed out. That means at least one update has expired.// Iterate through the root schedule. If they contain expired work, set// the next render expiration time to the current time. This has the effect// of flushing all expired work in a single batch, instead of flushing each// level one at a time.if (firstScheduledRoot ! null) {recomputeCurrentRendererTime();let root: FiberRoot firstScheduledRoot;do {didExpireAtExpirationTime(root, currentRendererTime);// The root schedule is circular, so this is never null.root (root.nextScheduledRoot: any);} while (root ! firstScheduledRoot);}}performWork(NoWork, true);} finally {didYield false;}
}function performSyncWork() {performWork(Sync, null);
}function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {deadline dl;// Keep working on roots until theres no more work, or until we reach// the deadline.findHighestPriorityRoot();if (deadline ! null) {recomputeCurrentRendererTime();currentSchedulerTime currentRendererTime;if (enableUserTimingAPI) {const didExpire nextFlushedExpirationTime currentRendererTime;const timeout expirationTimeToMs(nextFlushedExpirationTime);stopRequestCallbackTimer(didExpire, timeout);}while (nextFlushedRoot ! null nextFlushedExpirationTime ! NoWork (minExpirationTime NoWork ||minExpirationTime nextFlushedExpirationTime) (!deadlineDidExpire || currentRendererTime nextFlushedExpirationTime)) {performWorkOnRoot(nextFlushedRoot,nextFlushedExpirationTime,currentRendererTime nextFlushedExpirationTime,);findHighestPriorityRoot();recomputeCurrentRendererTime();currentSchedulerTime currentRendererTime;}} else {while (nextFlushedRoot ! null nextFlushedExpirationTime ! NoWork (minExpirationTime NoWork ||minExpirationTime nextFlushedExpirationTime)) {performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, true);findHighestPriorityRoot();}}// Were done flushing work. Either we ran out of time in this callback,// or theres no more work left with sufficient priority.// If were inside a callback, set this to false since we just completed it.if (deadline ! null) {callbackExpirationTime NoWork;callbackID null;}// If theres work left over, schedule a new callback.if (nextFlushedExpirationTime ! NoWork) {scheduleCallbackWithExpirationTime(((nextFlushedRoot: any): FiberRoot),nextFlushedExpirationTime,);}// Clean-up.deadline null;deadlineDidExpire false;finishRendering();
}performAsyncWork, performSyncWork, performWork 三个方法连在一起对于 performSyncWork 直接 调用 performWork(Sync, null); 就一行代码performAsyncWork 就相对复杂是通过 react scheduler 调度回来的 参数是 deadline 对象 dl本质上只有一个 if判断 和 执行 performWork 方法在if判断中 recomputeCurrentRendererTime 这个方法不涉及主要流程跳过 在找到 root 之后执行 didExpireaTexpirationTime 标记在root节点上的一些变量// packages/react-reconciler/src/ReactFiberPendingPriority.js
export function didExpireAtExpirationTime(root: FiberRoot,currentTime: ExpirationTime,
): void {const expirationTime root.expirationTime;// 有任务但任务过期if (expirationTime ! NoWork currentTime expirationTime) {// The root has expired. Flush all work up to the current time.root.nextExpirationTimeToWorkOn currentTime; // 挂载 当前时间 作为 nextExpirationTimeToWorkOn 属性}
}之后一个do while 找最终的 root 之后执行 performWork(NoWork, dl) NoWork 是 0export const NoWork 0 在 performWork 中 有两个参数minExpirationTime: ExpirationTime, dl: Deadline | nullfindHighestPriorityRoot 这个方法function findHighestPriorityRoot() {let highestPriorityWork NoWork;let highestPriorityRoot null;// 这个if表示仍存在节点更新情况if (lastScheduledRoot ! null) {let previousScheduledRoot lastScheduledRoot;let root firstScheduledRoot;// 存在 root 就进行循环while (root ! null) {const remainingExpirationTime root.expirationTime;// 这个if判断表示是没有任何更新的if (remainingExpirationTime NoWork) {// This root no longer has work. Remove it from the scheduler.// TODO: This check is redudant, but Flow is confused by the branch// below where we set lastScheduledRoot to null, even though we break// from the loop right after.invariant(previousScheduledRoot ! null lastScheduledRoot ! null,Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue.,);// 这种情况只有一个 root 节点if (root root.nextScheduledRoot) {// This is the only root in the list.root.nextScheduledRoot null;firstScheduledRoot lastScheduledRoot null;break;} else if (root firstScheduledRoot) {// 这时候 root 就没用了可以删除了获取 next// This is the first root in the list.const next root.nextScheduledRoot;firstScheduledRoot next;lastScheduledRoot.nextScheduledRoot next;root.nextScheduledRoot null;} else if (root lastScheduledRoot) {// 这个时候root是最后一个// This is the last root in the list.lastScheduledRoot previousScheduledRoot;lastScheduledRoot.nextScheduledRoot firstScheduledRoot;root.nextScheduledRoot null;break;} else {// 移除 中间的 root.nextScheduledRoot 节点previousScheduledRoot.nextScheduledRoot root.nextScheduledRoot;root.nextScheduledRoot null;}root previousScheduledRoot.nextScheduledRoot;} else {// 判断优先级更新更高优先级if (highestPriorityWork NoWork ||remainingExpirationTime highestPriorityWork) {// Update the priority, if its higherhighestPriorityWork remainingExpirationTime;highestPriorityRoot root;}if (root lastScheduledRoot) {break;}if (highestPriorityWork Sync) {// Sync is highest priority by definition so// we can stop searching.break;}previousScheduledRoot root;root root.nextScheduledRoot;}}}// 处理更新后的 highestPriorityRoot 和 highestPriorityWorknextFlushedRoot highestPriorityRoot;nextFlushedExpirationTime highestPriorityWork;
}看下 deadine 不为 null 时的情况 这是异步的情况主要看 while 里的 (!deadlineDidExpire || currentRendererTime nextFlushedExpirationTime) !deadlineDidExpire 表示时间片还有剩余时间nextFlushedExpirationTime 是现在要输出任务的过期时间 currentRendererTime nextFlushedExpirationTime说明 当前 render 时间 比 过期时间大已经超时了需要强制输出 之后执行 performWorkOnRoot 关于这个函数主要关注第三个参数默认是 true对于异步情况值为: currentRendererTime nextFlushedExpirationTime 任务过期则为 true, 否则为 false 进入 这个函数function performWorkOnRoot(root: FiberRoot,expirationTime: ExpirationTime,isExpired: boolean, // 是否过期这个方法里一定有针对过期任务的强制更新
) {invariant(!isRendering,performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.,);isRendering true; // 注意这里和函数结束// Check if this is async work or sync/expired work.// deadline null 是 Sync的情况isExpired 是过期的情况if (deadline null || isExpired) {// Flush work without yielding.// TODO: Non-yieldy work does not necessarily imply expired work. A renderer// may want to perform some work without yielding, but also without// requiring the root to complete (by triggering placeholders).let finishedWork root.finishedWork;if (finishedWork ! null) {// This root is already complete. We can commit it.completeRoot(root, finishedWork, expirationTime); // 有 finishedWork 直接 completeRoot} else {root.finishedWork null;// If this root previously suspended, clear its existing timeout, since// were about to try rendering again.const timeoutHandle root.timeoutHandle;// 处理 timeoutHandle 的情况跳过if (timeoutHandle ! noTimeout) {root.timeoutHandle noTimeout;// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check abovecancelTimeout(timeoutHandle);}// 在这个条件下不可中断 因为在上层if框架下要么是 Sync的任务要么是 过期的任务需要立即执行const isYieldy false;renderRoot(root, isYieldy, isExpired);finishedWork root.finishedWork;if (finishedWork ! null) {// Weve completed the root. Commit it.completeRoot(root, finishedWork, expirationTime);}}} else {// 这里匹配 Async 异步任务和上面Sync的任务流程基本差不多// Flush async work.let finishedWork root.finishedWork;// 一开始进来判断这个 finishedWork有可能在上一个时间片中renderRoot执行完了但是没有时间去执行 completeRoot 了// 需要再下次异步调度的时候进来如果有 finishedWork 则先 completeRootif (finishedWork ! null) {// This root is already complete. We can commit it.completeRoot(root, finishedWork, expirationTime);} else {root.finishedWork null;// If this root previously suspended, clear its existing timeout, since// were about to try rendering again.const timeoutHandle root.timeoutHandle;if (timeoutHandle ! noTimeout) {root.timeoutHandle noTimeout;// $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check abovecancelTimeout(timeoutHandle);}// 这个任务是可以中断的const isYieldy true;renderRoot(root, isYieldy, isExpired);finishedWork root.finishedWork;// finishedWork 有可能为 null, 中断了就没有完成任务if (finishedWork ! null) {// Weve completed the root. Check the deadline one more time// before committing.// 先判断是否需要跳出这时候时间片可能已经用完如果没有用完执行 completeRootif (!shouldYield()) {// Still time left. Commit the root.completeRoot(root, finishedWork, expirationTime);} else {// Theres no time left. Mark this root as complete. Well come// back and commit it later.// 需要跳出则赋值 finishedWork注意这里不执行 completeRoot因为没有时间了需要等待下个时间片进来才能执行root.finishedWork finishedWork;}}}}isRendering false;
}执行 findHighestPriorityRootcurrentSchedulerTime currentRendererTime 看下 deadine 为 null 时的情况 这是同步的情况while(nextFlushedRoot ! null nextFlushedExpirationTime ! NoWork (minExpirationTime NoWork || minExpirationTime nextFlushedExpirationTime)) 对于 perfromSyncWork 来说minExpirationTime 是 11 nextFlushedExpirationTime 说明 只有 Sync(1)的情况或者 NoWork所以 nextFlushedExpirationTime 只有是1的情况相当于在 perfromSyncWork 的时候只会执行 root.expirationTime 是 Sync 的任务也就是说是同步更新的更新才会在这里继续执行这样和 SyncWork 这函数名匹配在这种情况下调用 performWorkOnRoot 和 findHighestPriorityRoot 执行掉 Sync的任务 注意在 performWork 上两个循环的判断条件以及传入 performWorkOnRoot的第三个参数的意义