网站优化反馈机制 seo,资讯文章类wordpress博客模板,查询关键词排名软件,天河建网站公司requestWork 1 #xff09;概述
在 scheduleWork 中#xff0c;找到了创建更新的fiber对应的root节点然后对它进行了一些操作之后#xff0c;调用了 requestWork#xff0c;开始请求工作在 requestWork 里面它会做哪些东西呢#xff1f; 首先我们要把这个root节点加入到调…requestWork 1 概述
在 scheduleWork 中找到了创建更新的fiber对应的root节点然后对它进行了一些操作之后调用了 requestWork开始请求工作在 requestWork 里面它会做哪些东西呢 首先我们要把这个root节点加入到调度队列当中然后判断是否是批量更新最后再根据 expirationTime 的类型来判断调度的类型
2 源码
react-reconciler/src/ReactFiberScheduler.js 找到 requestWork
// requestWork is called by the scheduler whenever a root receives an update.
// Its up to the renderer to call renderRoot at some point in the future.
function requestWork(root: FiberRoot, expirationTime: ExpirationTime) {addRootToSchedule(root, expirationTime);if (isRendering) {// Prevent reentrancy. Remaining work will be scheduled at the end of// the currently rendering batch.return;}if (isBatchingUpdates) {// Flush work at the end of the batch.if (isUnbatchingUpdates) {// ...unless were inside unbatchedUpdates, in which case we should// flush it now.nextFlushedRoot root;nextFlushedExpirationTime Sync;performWorkOnRoot(root, Sync, true);}return;}// TODO: Get rid of Sync and use current time?if (expirationTime Sync) {performSyncWork();} else {scheduleCallbackWithExpirationTime(root, expirationTime);}
}这里它接受的参数 一个是 root另外一个是 expirationTime 这个 expirationTime 并不是我们在创建更新的时候的 expirationTime它是经过一系列处理之后得到的 expirationTime它是用来记录任务的过期时间的 进来之后的第一个方法是 addRootToSchedulefunction addRootToSchedule(root: FiberRoot, expirationTime: ExpirationTime) {// Add the root to the schedule.// Check if this root is already part of the schedule.if (root.nextScheduledRoot null) {// This root is not already scheduled. Add it.root.expirationTime expirationTime;if (lastScheduledRoot null) {firstScheduledRoot lastScheduledRoot root;root.nextScheduledRoot root;} else {lastScheduledRoot.nextScheduledRoot root;lastScheduledRoot root;lastScheduledRoot.nextScheduledRoot firstScheduledRoot;}} else {// This root is already scheduled, but its priority may have increased.const remainingExpirationTime root.expirationTime;if (remainingExpirationTime NoWork ||expirationTime remainingExpirationTime) {// Update the priority.root.expirationTime expirationTime;}}
}判断 if (root.nextScheduledRoot null) , 符合则进行更新 说明这个 root 之前没有进入过调度内部如果 lastScheduledRoot 为空 注意 firstScheduledRoot 和 lastScheduledRoot 是单项链表结构用于存储react中的所有 root 的调度关系如果存在多个root, 可能会形成一个链表的结构对于只有一个root的情况只会存在 root.nextScheduledRoot root 即等于自己这种情况这种情况会出现是因为先有了一个异步调度的任务因为一次一个时间片内执行不完执行不完把JS的执行权交给浏览器浏览器这个时候触发了 react 当中的一个新的更新然后这个更新进来的时候在react里面它总共有两种不同优先级的更新这个时候就会调用两次 addRootToSchedule这个时候 root.nextScheduledRoot root 就等于它自己当然也会存在着有多个root的情况这个时候就会形成一个链条这边就是通过判断是否存在 lastScheduledRoot 来判断现在是否有任务正在进行调度如果没有的话我们就把first和last直接赋值成root就可以了那如果有的话更新 lastScheduleddRoot及其nextSchedulRoot这就是一个把当前的这个root插到这个调度队列的最后一个的操作即单项链表插入到最后一个的操作 如果已经进入过调度 获取当前的 expirationTime 并进行判断如果当前的 expirationTime 是 NoWork 或 新的调度的 expirationTime 比当前任务优先级大则更新 root.expirationTime 成最高优先级因为 expirationTime 必须是 root 上优先级最高的我们要先执行优先级高的任务对于 root 来说如果是一个异步调度expirationTime 最小的任务过期时间最少进入到后期调度的过程中按照比它优先级低的来做等到它的过期时间到了我们的调度进程中的判断标准还没有认为过期就不会强制执行从而导致任务被推迟所以必须把 root.expirationTime 设置成优先级最高的 接下来判断是否在渲染中if (isRendering) 说明调度在执行了这里直接 returnreact 的调度是有个循环的会循环 firstScheduledRoot 和 lastScheduledRoot 上面的任务最终把所有任务更新完之后把 firstScheduledRoot 和 lastScheduledRoot 清空成 nullisRendering 说明循环已经开始直接return就行 接下来进入批处理的判断, if (isBatchingUpdates) isBatchingUpdates 和 isUnbatchingUpdates 是两个全局变量是批处理相关的先跳过 最后通过 expirationTime是否为 Sync的判断 如果是 Sync则调用 performSyncWork 方法 相当于同步调用 js 代码一直执行到结束为止无法被打断如果层级很深则会占用js较长时间可能导致应用卡顿在以前版本没有 async 的情况都是执行 performSyncWork这样它的瓶颈是很大的性能不好在 react16之后保留了 sync 的模式因为应用可能需要这种场景 如果不是则调用 scheduleCallbackWithExpirationTime 方法 这里进行异步的调度这里进入了 react 中的独立的包 scheduler这个包帮我们使用类似 requestIdleCallback 的方式帮助我们在浏览器有空闲的情况下去执行不是很重要的任务并且给我们设置 deadline在 deadline 之前可以执行在这个 deadline 之后必须先把执行权交还给浏览器再等它有空再来执行任务这个包用于提升前端应用开发的效率