网站如何防止重登录,网站开发工程师证书有用吗,wordpress模板自适应,登录网站模板React调度原理(scheduler)
在React运行时中#xff0c;调度中心#xff08;位于scheduler包#xff09;是整个React运行时的中枢#xff08;其实是心脏#xff09;#xff0c;所以理解了scheduler调度#xff0c;就基本掌握了React的核心React两大循环#xff1a;从宏…React调度原理(scheduler)
在React运行时中调度中心位于scheduler包是整个React运行时的中枢其实是心脏所以理解了scheduler调度就基本掌握了React的核心React两大循环从宏观的角度介绍 React 体系中两个重要的循环其中任务调度循环就是本文的主角Reconciler 运行流程从宏观的角度描述了 react-reconciler 包的核心作用 并把 reconciler 分为了4个阶段其中第 2 个阶段注册调度任务串联了 scheduler 包和 react-reconciler 包其实就是任务调度循环中的一个任务(task) 优先级管理 React体系中的3中优先级的管理着重源码中react-reconciler与scheduler包中关于优先级的转换思路其中 SchedulerPriority 控制任务调度循环中循环的顺序
调度实现
调度中心最核心的代码在 SchedulerHostConfig.default.js 中
内核
该js文件一共导出了8个函数最核心的逻辑就集中在了这8个函数中export let requestHostCallback; // 请求及时回调 port.postMessage
export let cancelHostCallback; // 取消及时回调 scheduledHostCallback null
export let requestHostTimeout; // 请求延时回调 setTimeout
export let cancelHostTimeout; // 取消延时回调 cancelTimeout
export let shouldYieldToHost; // 是否让出主线程 (currentTime - deadline needsPaint):
export let requestPaint; // 请求绘设置 needsPaint true
export let getCurrentTime; // 获取当前间
export let forceFrameRate; // 强制设置 yieldIntervol (让出主线程的周期)react可以在nodejs环境中使用所以在不同的js执行环境中这些函数的实现会有区别下面基于普通浏览器环境对这8个函数逐一分析
1 调度相关请求或取消调度 requestHostCallback cancelHostCallback requestHostTimeout cancelHostTimeout 这4个函数源码很简洁非常好理解它们的目的就是请求执行或取消回调函数 现在重点介绍其中的及时回调 (延时回调的2个函数暂时属于保留api,17.0.2版本其实没有用上) // MessageChannel
const performWorkUntilDeadline() {//...省略无关代码if (scheduledHostCallback ! null) {const currentTime getCurrentTime();// 更新 deadlinedeadline currentTime yieldInterval;// 执行 callbackscheduledHostCallback(hasTimeRemaining, currentTime);} else {isMessageLoopRunning false;};
};const channel new MessageChannel();
const port channel.port2;
channel.port1.onmessage performWorkUntilDeadline;// 请求回调
requestHostCallback function(callback) {// 1.保存callbackscheduledHostCallback callback;if(!isMessageLoopRunning) {isMessageLoopRunning true;// 2.通过 MessageChannel消息port.postMessage(null);}
};// 取消回调
cancelHostCallback function() {scheduledHostCallback null;
}很明显请求回调之后 scheduledHostCallback callback 然后通过MessageChannel发消息的方式触发performWorkUntilDeadline函数 最后执行回调 scheduledHostCallback 此处需要注意 MessageChannel在浏览器事件循环中属于宏任务所以调度中心永远是异步执行回调函数
2 时间切片(timeslicing)相关 执行时间分割让出主线程 把控制权归还浏览器浏览器可以处理用户输入UI绘制等紧急任务 getCurrentTime: 获取当前时间 shouldYieldToHost: 是否让出主线程 requestPaint: 请求绘制 forceFrameRate: 强制设置yieldInterval(从源码中的引用来看算一个保留函数其他地方没有用到) const localPerformance performance;
// 获取当前时间
getCurrentTime () localPerformance.now();// 时间切片周期默认是5ms(如果一个task运行超过该周期下一个task执行之前会把控制权归还浏览器)
let yieldInterval 5;
let deadline 0;
const maxYieldInterval 300;
let needsPaint false;
const scheduling navigator.scheduling;
// 是否让出主线程
shouldYieldToHost function() {const currentTime getCurrentTime();if (currentTime deadline) {if (needsPaint || scheduling.isInputPending()) {// There is either a pending paint or a pending input.return true;}// Theres no pending input. Only yield if weve reached the max// yield interval.return currentTime maxYieldInterval; // 在持续运行的react应用中 currentTime肯定大于300ms} else {// Theres still time left in the frame.return false;}
};// 请求绘制
requestPaint function() {needsPaint true;
};// 设置时间切片的周期
forceFrameRate function(fps) {if (fps 0 || fps 125) {// Using console[error] to evade Babel and ESLintconsole[error](forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported,);return;}if (fps 0) {yieldInterval Math.floor(1000 / fps);} else {// reset the framerateyieldInterval 5;};
}这4个函数代码都很简洁其功能在注释中都有解释. 注意 shouldYieldToHost 的判定条件 currentTime deadline: 只有时间超过 deadline 之后才会让出主线程其中 deadline currentTime yieldInterval yieldInterval 默认是5ms, 只能通过 forceFrameRate 函数来修改如果一个task运行时间超过5ms,下一个task执行之前会把控制权归还浏览器 navigator.scheduling.isInputPending(): 这facebook官方贡献给 Chromium 的api,现在已经列入W3C标准用于判断是否有输入事件包括input框输入事件点击事件等. 看完这8个内部函数最后浏览一下完整的 performWorkUntilDeadline 回调的实现 const performWorkUntilDeadline () {if(scheduledHostCallback ! null) {const currentTime getCurrentTime(); //1.获取当前时间deadline currentTime yieldInterval; //2. 置deadline 当前时间 5ms, 也就是5ms超时const hasTimeRemaining true;try {// 3.执行回调返回是否有还有剩余任务const hasMoreWork scheduledHostCallback(hasTimeRemaining, currentTime);if (!hasMoreWork) {// 没有剩余任务退出isMessageLoopRunning false;scheduledHostCallback null;} else {port.postMessage(null); // 有剩余任务发起新的调度}} catch (error) {port.postMessage(null); // 如有异常重新发起调度throw error;}} else {isMessageLoopRunning false;}needsPaint false; // 重置开关
}核心总结如下图 MessageChanel 里面是宏任务异步执行在执行的过程中基于 performWorkUnitlDeadline这个方法在执行任务过程中有一个变量 hasMoreWork基于这个变量判断是否还有任务如果还有则继续往里面注册回调没有则退出