当前位置: 首页 > news >正文

React Scheduler(调度器)

React Scheduler(调度器)是实现“非阻塞渲染”的核心模块,其核心原理是通过优先级区分任务、利用浏览器空闲时间分片执行任务,避免长任务阻塞UI线程。以下从「优先级设计」「任务调度机制」「浏览器协作策略」三个维度详细解析:

一、核心目标:解决“同步渲染阻塞问题”

在React 15及之前,组件渲染是同步递归执行的:一旦开始渲染,会持续占用JS线程直到完成。如果遇到复杂组件树(如1000个列表项),会阻塞浏览器的用户交互(点击、输入)、动画等关键操作,导致页面卡顿。

Scheduler的出现就是为了实现**“可中断的异步渲染”**:

  • 将长任务拆分成多个短任务(“切片”);
  • 每个短任务执行后,主动让出JS线程给浏览器;
  • 浏览器处理完UI事件、动画后,再继续执行剩余任务。

二、优先级设计:给任务“贴标签”,决定执行顺序

Scheduler将任务分为5级优先级(从高到低),不同类型的更新对应不同优先级,确保关键操作(如用户输入)优先执行:

优先级常量对应场景特点
ImmediatePriority同步执行的紧急任务(如flushSync立即执行,不延迟
UserBlockingPriority用户交互(点击、输入、滚动)高优先级,25ms内必须执行完毕
NormalPriority普通更新(如setState正常优先级,50ms内执行完毕
LowPriority低优先级更新(如列表渲染)可延迟,100ms内执行完毕
IdlePriority空闲时执行的任务(如日志上报)仅在浏览器完全空闲时执行

优先级的本质:通过「过期时间」(expirationTime)表示——优先级越高,过期时间越近(即“越快必须执行”)。例如:

  • UserBlockingPriority 的过期时间 = 当前时间 + 25ms;
  • 如果任务执行时已超过过期时间,会被视为“紧急任务”,同步执行剩余部分。

三、任务调度的核心机制

Scheduler的工作流程可概括为:“入队→排序→执行→中断→恢复”,具体通过以下关键步骤实现:

1. 任务入队:用“小顶堆”存储任务
  • 当调用 scheduleCallback(priority, callback) 时,Scheduler会创建一个「任务对象」:
    const task = {callback,       // 任务函数(如组件渲染逻辑)priorityLevel,  // 优先级等级expirationTime, // 过期时间(决定执行顺序)...
    };
    
  • 任务被加入「优先级队列」,队列采用小顶堆(min-heap)数据结构,确保每次能快速取出「过期时间最近」(优先级最高)的任务。
2. 任务执行:“切片执行”+“浏览器协作”

Scheduler通过 requestHostCallback 启动任务循环,核心逻辑如下:

  • 步骤1:取出最高优先级任务
    从堆中取出过期时间最近的任务,执行其 callback 函数。

  • 步骤2:执行任务切片
    任务函数执行时,会返回一个“剩余任务函数”(如果任务未完成)。例如:

    // 任务函数示例(伪代码)
    function taskCallback(didUserCallbackTimeout) {// 执行一部分工作(如渲染10个列表项)const moreWork = doSomeWork(); if (moreWork) {// 返回剩余任务,后续继续执行return taskCallback; }return null; // 任务完成
    }
    
  • 步骤3:检查是否需要让出线程
    每次任务切片执行后,Scheduler会检查:

    • 是否已超过浏览器的“空闲时间片”(通常是5ms);
    • 是否有更高优先级的新任务插入队列。
      如果满足任一条件,立即暂停当前任务,让出JS线程。
3. 中断与恢复:利用浏览器API实现协作

Scheduler依赖浏览器的空闲时间API实现线程让出,核心是 requestIdleCallbacksetTimeout 的降级方案:

  • 理想情况:使用 requestIdleCallback,浏览器在空闲时(如帧渲染完成后)回调通知Scheduler继续执行任务;
  • 降级情况requestIdleCallback 兼容性差且延迟较高,Scheduler实际使用 setTimeout(0) 模拟“宏任务延迟”,确保任务能被中断。

恢复执行:当浏览器空闲或延迟时间到达后,Scheduler再次调用 requestHostCallback,从堆中取出任务继续执行,直到所有任务完成。

四、关键代码解析:核心函数的协作流程

Scheduler的核心逻辑集中在 scheduler/src/Scheduler.js 中,以下是关键函数的协作关系:

  1. scheduleCallback:任务入队入口

    • 根据优先级计算 expirationTime
    • 创建任务对象并插入小顶堆;
    • 调用 requestHostCallback 启动任务循环。
  2. requestHostCallback:触发任务执行

    • 向浏览器注册“空闲时回调”(通过 schedulePerformWorkUntilDeadline);
    • 浏览器空闲时,会调用 performWorkUntilDeadline
  3. performWorkUntilDeadline:任务执行循环

    • 从堆中取出最高优先级任务;
    • 执行任务的 callback 函数,获取剩余任务;
    • 检查是否超时或有更高优先级任务,决定是否继续执行或中断;
    • 若有剩余任务,再次注册回调等待下一次空闲时间。
  4. cancelCallback:取消任务

    • 将任务标记为已取消,避免被执行;
    • 后续从堆中取出任务时,会跳过已取消的任务。

五、与React Fiber架构的配合

Scheduler并非孤立存在,而是与Fiber架构深度协作,实现“可中断的渲染”:

  • Fiber的“切片渲染”:React的Reconciler(协调器)将组件树遍历拆分成一个个Fiber节点的处理(每个节点处理即一个“切片”),每次处理完一个节点,就会检查Scheduler是否需要中断;
  • 优先级对齐:Fiber节点的更新优先级(通过Lane模型表示)与Scheduler的任务优先级对应,确保高优先级的更新(如用户输入)能打断低优先级的渲染(如列表渲染)。

总结:Scheduler的核心价值

Scheduler通过**“优先级分级”“小顶堆排序”“浏览器空闲时间利用”**三大机制,解决了React同步渲染的性能问题,使得:

  1. 高优先级任务(如用户输入)能优先执行,避免卡顿;
  2. 长任务被拆分成切片,逐步执行,不阻塞UI线程;
  3. 为后续Concurrent Mode(并发模式)、Suspense等特性提供了基础支撑。

理解Scheduler的关键是抓住“任务优先级”和“浏览器协作”两个核心,这也是React性能优化的底层逻辑。


文章转载自:

http://9JeQcICt.mxrbm.cn
http://oi0MnW5a.mxrbm.cn
http://xAnTfYNG.mxrbm.cn
http://EZMR9rWn.mxrbm.cn
http://qH5m5UTQ.mxrbm.cn
http://OSTbTD6F.mxrbm.cn
http://8T2bGcxt.mxrbm.cn
http://Mq3yVZ2m.mxrbm.cn
http://vLxieaJw.mxrbm.cn
http://OPPuMKzi.mxrbm.cn
http://GrdJwNVw.mxrbm.cn
http://E5q9mFCl.mxrbm.cn
http://FHQZNkRA.mxrbm.cn
http://swMiLelB.mxrbm.cn
http://ypq6OHPe.mxrbm.cn
http://uKgXpubl.mxrbm.cn
http://0jQLXirl.mxrbm.cn
http://Ifw6jO8E.mxrbm.cn
http://wRTRqi5M.mxrbm.cn
http://DDNR77Nl.mxrbm.cn
http://B9tHG2Aj.mxrbm.cn
http://3U6Tqa7y.mxrbm.cn
http://qO50ME8L.mxrbm.cn
http://8pYyu55l.mxrbm.cn
http://gs8JFXFy.mxrbm.cn
http://fHg4NPAu.mxrbm.cn
http://nszvjDel.mxrbm.cn
http://jh2E8EtR.mxrbm.cn
http://vrZAuj5c.mxrbm.cn
http://cWrds4jj.mxrbm.cn
http://www.dtcms.com/a/385255.html

相关文章:

  • 多任务数据集的具体使用场景
  • KITTI数据集
  • 什么云服务器更好用推荐一下!?
  • 根据Linux内核原理 LRU链表如何知道page的活动频繁程度?
  • 2025全球LoRaWAN模组技术对比与应用方案解析
  • 社区主题征文——「异构融合与存算一体:架构探索与创新实践」算力技术征文
  • Jenkins参数化构建
  • SIPJS对接FreeSWITCH强制媒体流走coturn relay地址
  • docker registry 私服搭建教程
  • 清除gradle缓存的某个依赖
  • MCP引导Agent示例
  • 【HTTP 响应状态码】从零到实战
  • 航线系统对频模块技术要点
  • 二十、DevOps落地:Jenkins基础入门(一)
  • 计网1.1
  • DDD领域驱动设计
  • 传智播客--MySQL
  • 不同 HLA II 类等位基因(HLA-DRB1*15:02)与 cGVHD 的关联差异
  • 【AI 辅助工作工具集合】持续更新
  • 核心信息防爬虫盗取技术方案
  • Linux网络:序列化和反序列化
  • Java 代理模式-JDK动态代理
  • RabbitMQ 消息持久化与可靠性
  • 基于YOLO8的打架斗殴行为检测系统【源码+数据集+文章】
  • 电磁超声螺栓轴力检测技术:破解法兰泄露与设备安全痛点的关键方案
  • GPT-5深度解析:它真的是AGI的拂晓晨光吗?
  • (播放器开发)音频输出
  • 视频转音频在线工具大比拼,哪家体验更胜一筹?
  • 如何选择合适的工业绝缘监测仪
  • 【沉浸式解决问题】iPhone 6 登录苹果ID时一直跳出 unexpected error with certificate 或 无法登录