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

Fiber、协程和 Generator行为上的区别?

“可中断”和“可恢复” 确实是 Fiber、协程和 Generator 在行为上最显著的共同点。

它们的巨大差异在于 “如何实现” 以及 “为何而设计”

让我们深入底层,看看 yield/next 和 Fiber 分别是如何运作的。


1. Generator 如何实现中断与恢复?(语言层面的魔法)

Generator 的中断恢复是 JavaScript 引擎在语言层面提供的原生能力

核心机制:执行上下文的保存与切换

当您调用一个 Generator 函数 function* gen() 时,引擎并不会立即执行它,而是返回一个 迭代器对象
当您调用 iterator.next() 时,引擎会:

  1. 创建/恢复一个独立的执行上下文:这个上下文包含了 Generator 函数内部的局部变量、参数、以及当前执行到的位置。
  2. 执行直至 yield:引擎在这个独立的上下文中执行代码,直到遇到 yield 关键字。
  3. 暂停并交出值:遇到 yield 时,引擎立即冻结当前的执行上下文,并将 yield 后面的值包装成 {value: ..., done: false} 返回给调用者。这个上下文被完整地保存在堆内存中。
  4. 等待下一次 next:函数调用似乎“返回”了,主线程可以去做其他事情。当再次调用 iterator.next() 时,引擎会找到之前冻结的上下文,将其解冻并完全恢复,从上次 yield 语句之后继续执行。

可以把它想象成:
引擎给这个 Generator 函数拍了一张快照yield 时保存快照并暂停,next() 时则把快照加载回来继续播放。这个“拍快照”的能力是 JS 引擎内置的,开发者无法直接控制。


2. Fiber 如何实现中断与恢复?(应用层面的模拟)

Fiber 的中断恢复是 React 团队在 JavaScript 应用层,用代码模拟出来的能力。因为 React 无法改变 JS 引擎。

核心机制:链表数据结构 + 循环模拟递归

  1. 数据结构:Fiber 节点链表
    React 将虚拟 DOM 树转换成了一个由 Fiber 节点组成的链表。每个 Fiber 节点对应一个组件,并包含以下信息:

    • child: 指向第一个子节点。
    • sibling: 指向下一个兄弟节点。
    • return: 指向父节点。
    • stateNode: 组件实例或 DOM 节点。
    • alternate: 指向当前节点对应的上一次渲染的 Fiber 节点(用于 Diff 比较)。

    这就是“可恢复”的秘密所在:所有的工作状态都明确地存储在这个链表数据结构里,而不是依赖调用栈。

  2. 执行过程:循环和手动记录
    React 不再使用递归来遍历树。递归一旦开始就无法中断,因为调用栈的信息由引擎管理。
    取而代之,React 实现了一个 workLoop(工作循环),它基于 requestIdleCallback(或 setTimeout)来在一帧的空闲时间里执行任务。

    这个循环大概是这样的:

    let nextFiberUnitOfWork = null; // 下一个要处理的Fiber节点(这就是“恢复”点)
    let shouldYield = false; // 是否该中断了function workLoop(deadline) {while (nextFiberUnitOfWork && !shouldYield) {// 1. 处理当前Fiber节点(“执行”)nextFiberUnitOfWork = performUnitOfWork(nextFiberUnitOfWork);// 2. 检查当前帧是否还有剩余时间shouldYield = deadline.timeRemaining() < 1;}// 3. 如果时间不够了,就中断循环,并请求下一次空闲周期再继续if (nextFiberUnitOfWork) {requestIdleCallback(workLoop);}
    }// 开始工作
    requestIdleCallback(workLoop);
    
  3. performUnitOfWork 函数
    这个函数是核心,它做三件事:

    • Begin:处理当前 Fiber 节点(如调用 Render、Diff 子节点)。
    • 向下遍历:如果有子节点,返回子节点作为下一个工作单元。
    • 向上/向右遍历:如果没有子节点,就处理兄弟节点。如果没有兄弟节点,就“完成”当前节点并返回父节点

    通过总是返回下一个要处理的节点,React 完全摆脱了对调用栈的依赖。中断时,它只需要记录下 nextFiberUnitOfWork 这个变量。恢复时,工作循环直接从上次记录的这个节点开始继续处理即可。


对比与总结

特性Generator (yield/next)React Fiber
实现层级语言引擎层。由 JS 规范定义,引擎原生支持。应用层。React 用纯 JavaScript 代码和数据结构模拟实现。
中断/恢复原理冻结/解冻执行上下文。引擎魔法,效率高但不可见。手动记录链表遍历的指针。通过循环和返回“下一个节点”来模拟。状态完全保存在 Fiber 节点数据结构中。
控制权协同式 (Cooperative)。函数通过 yield 主动让出控制权。调度式 (Preemptive)。由外部的 调度器 (Scheduler) 根据优先级和剩余时间强制中断。
状态保存由引擎自动保存完整的函数执行上下文。由 React 显式地保存在 Fiber 节点的数据结构中。
目标为解决迭代和异步编程问题,提供一种通用的控制流机制。为解决 UI 渲染阻塞问题,实现可中断的渲染和优先级调度。

为什么 React 不直接用 Generator?

正如上面的对比所示:

  1. 功能不足:Generator 的“主动让出”模型无法实现 React 需要的基于优先级的“强制中断”。高优先级的更新(如用户输入)无法打断一个正在执行的 Generator 函数。
  2. 开销问题:Generator 的上下文保存和恢复虽然高效,但对于 React 大量、频繁的更新操作来说,依然是不够的。Fiber 的手动控制可以做到更极致的优化。
  3. 状态承载:React 需要承载的信息远不止函数内部的几个变量,而是整个组件的状态、副作用、子节点关系等。Fiber 的链表结构是专为这个目的设计的完美载体,而 Generator 的上下文对此并不知情。

简单比喻:

  • Generator 像是一本自带书签的书,你看累了可以主动夹上书签(yield),下次从书签处继续读(next)。
  • Fiber 像是你正在拼一个巨大的乐高模型。你无法让时间停止,但你可以在下班时用手机拍一张照片,记录下拼到哪一步了(这就是 nextFiberUnitOfWork)。明天上班,看着照片就能继续拼。这个“拍照记录”的行为,就是 Fiber 在应用层模拟的“中断与恢复”。
http://www.dtcms.com/a/400288.html

相关文章:

  • 朝阳区建设工作办公室网站wordpress json
  • 乐山网站开发公司电话用自己的电脑做网站服务器
  • 屏山县建设局网站网站开发能赚钱吗
  • 昌平网站开发自己做网站需要什么条件
  • 昆明网站排名比百度还强大的搜索引擎
  • niche网站建设机械加工网配件销售网
  • 嘉兴做网站费用电话销售电销系统
  • 网站深度功能全网热度指数
  • 变电站智能激光语音综合驱鸟器的适用场景有哪些?
  • codex + windows 环境下使用 serena mcp
  • 测试方案缺少测试设计的推导过程-如何补充
  • 建设网站 翻译儋州个人建站哪家好
  • 网站推广技巧有哪些软件下载类型网站怎么做
  • IP地址管理:docker方式部署phpIPAMv1.7.3
  • 郑州一建集团工程建设有限公司网站网络公司哪个最好
  • 使用 LLVM 16.0.4 编译 MiBench 中的 patricia遇到的 rpc 库问题
  • 第一章:Qt概述
  • 榆次做企业网站猎头公司属于什么行业
  • 江苏省宿迁市建设局网站首页小内存vps WordPress
  • 如何利用网站赚钱网站地图调用
  • 手机网站分辨率做多大logo设计网站国外
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘torchaudio’ 问题
  • 4.DSP学习记录之直流电机和步进电机驱动
  • 苏州做网站的公司怎么把网站放到空间吗
  • 网站建设发展现状免费ppt课件下载网站
  • 站长之家seo查询凡科互动app
  • 推广免费网站创建全国文明城市我们应该怎么做
  • 做网站用花瓣上的图片会侵权吗thinkphp做的教育网站
  • 移动端性能监控探索:鸿蒙 NEXT 探针架构与技术实现
  • 我想在泉州做网站wordpress分类不同模板