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

关于 Babel 编译后的 Generator 状态机结构解析

一、为什么 Babel 要编译成 Generator?

老版本浏览器不支持 async/await,所以 Babel 会:

async function fn() {                      // 定义一个异步函数 fn,使用 async 关键字表明函数内部可以使用 awaitconst res = await getData();            // 调用异步函数 getData(),等待其执行完成后,将返回值赋给 res 变量return res + 1;                         // 返回 res 加 1 的结果;这个 return 的结果会自动被封装成一个 Promise 对象
}

编译成:

var fn = _asyncToGenerator(                    // 调用 _asyncToGenerator 把一个 Generator 函数转成支持 Promise 的 async 函数regeneratorRuntime.mark(function* _callee() { // 使用 regeneratorRuntime.mark 包装一个 Generator 函数,生成器函数名为 _calleevar res;                                   // 定义变量 res,用于存放 getData 的返回结果return regeneratorRuntime.wrap(function (_context) { // 包装内部状态控制逻辑(状态机),_context 管理执行流程while (1) switch (_context.prev = _context.next) { // 状态机循环,通过 switch 和 _context 控制流程跳转case 0:                                 // case 0:初始状态_context.next = 2;                    // 跳转到状态 2,并执行 yield 表达式(实际是 await)return getData();                     // yield getData(),此处暂停,等待 Promise 返回(相当于 await getData())case 2:                                 // case 2:getData 执行完成,结果通过 _context.sent 获取res = _context.sent;                  // 把 yield 表达式(即 getData())的返回值赋给 res_context.abrupt("return", res + 1);   // 立即中断函数并返回 res + 1,相当于 return res + 1}}, _callee);                                // 绑定到 _callee 生成器函数上})
);

二、结构总览(模块分解)

编译后核心结构包括这几个部分:

名称解释
_asyncToGenerator()把 Generator 包装成异步 Promise
regeneratorRuntime.mark(fn)把函数标记为 Generator
regeneratorRuntime.wrap(fn)把函数包裹成状态机控制结构
while (1) switch(...)状态切换结构
_context.next跳转到下一个状态
_context.sent获取上一个 yield/await 的返回值
_context.abrupt()立即返回或退出当前状态

三、状态机结构详解

源码:

async function test() {const a = await getData();const b = await parseData(a);return b;
}

编译后:

var test = _asyncToGenerator(                // _asyncToGenerator:将生成器函数转换为返回 Promise 的函数(兼容 async)regeneratorRuntime.mark(function* () {     // regeneratorRuntime.mark:将匿名 Generator 函数进行注册和标记var a, b;                                // 定义两个变量 a 和 b,用来存储异步操作的结果return regeneratorRuntime.wrap(function (_context) { // 包装状态机,_context 是内部上下文控制器while (1) switch (_context.prev = _context.next) { // 无限循环 + 状态切换机制(状态机)case 0:                              // 初始状态 case 0_context.next = 2;                 // 设置下一步跳转到 case 2,同时 yield 一个异步操作return getData();                  // yield getData(),相当于 await getData(),暂停执行等待结果case 2:                              // 等 getData() Promise resolve 后,跳转到这里a = _context.sent;                 // 获取 getData() 的结果,赋值给变量 a_context.next = 5;                 // 设置下一步为 case 5return parseData(a);               // yield parseData(a),等价于 await parseData(a)case 5:                              // 等 parseData() 执行完后跳到这里b = _context.sent;                 // 获取 parseData(a) 的结果,赋值给变量 b_context.abrupt("return", b);      // 立即中断并返回 b,等价于 return b}});})
);

四、状态转移图解

状态是通过 switch (_context.prev = _context.next) 控制的:

状态 0 → _context.next = 2return getData();          // await getData()状态 2 → a = _context.sent_context.next = 5return parseData(a);   // await parseData(a)状态 5 → b = _context.sentreturn b;              // return 结果

每个 case 就是一个逻辑步骤。每次 return 表示 await每次 sent 是拿返回值


五、关键语句详解

语句作用等价于原始 JS
_context.next = N; return foo();执行 foo,并跳转到第 N 步await foo();
res = _context.sent;拿到上一步 yield 的结果const res = await xxx;
_context.abrupt("return", xxx);提前退出函数,返回值为 xxxreturn xxx;

六、执行流程详解(配图思维)

async function fn() {const res = await getData(); // Step 1await saveData(res);         // Step 2return "done";               // Step 3
}

变成:

switch (_context.prev = _context.next) {       // 状态机入口,切换执行状态case 0:                                       // 第 0 步,初始状态_context.next = 2;                          // 指定下一步为 case 2return getData();                           // step 1:执行 getData(),暂停函数等待 Promise 结果(相当于 await getData())case 2:                                       // 第 2 步,getData() 执行完,继续执行res = _context.sent;                        // 获取 getData() 的结果,赋值给 res(相当于 const res = await getData())_context.next = 5;                          // 指定下一步为 case 5return saveData(res);                       // step 2:执行 saveData(res),暂停函数等待 Promise 结果(相当于 await saveData(res))case 5:                                       // 第 5 步,saveData(res) 执行完,继续执行_context.abrupt("return", "done");          // step 3:返回 "done",终止 Generator(相当于 return "done")
}

每一步是状态跳转 + 执行 + 下一步


七、如何手动还原 async/await?

只需 3 步

  • _context.next = N; return xxx → 就是 await xxx

  • xxx = _context.sent; → 表示上一步结果赋值

  • _context.abrupt("return", ...) → 函数的 return


八、技巧总结

实战分析点如何应对
_context.sent找到结果变量,理解 await 获取值
_context.next理解跳转执行顺序
abrupt("return")确定退出函数并返回值
多层嵌套 Generator拆解并逐步打印每层函数
http://www.lqws.cn/news/508861.html

相关文章:

  • 读取ILA数据进行MATLAB分析
  • 软件行业如何权衡“统一规范“与“灵活创新“?
  • Vue.js 列表过滤实现详解(watch和computed实现)
  • PYTHON从入门到实践4-数据类型
  • 原子操作(CAS)
  • OSS跨区域复制灾备方案:华东1到华南1的数据同步与故障切换演练
  • 嵌入式开发学习日志Day8(ARM体系架构——按键、蜂鸣器及中断)
  • 【bug】searchxng搜索报错Searx API returned an error
  • Vue项目使用defer优化页面白屏,性能优化提升,秒加载!!!
  • java-SpringBoot框架开发计算器网页端编程练习项目【web版】
  • QT多线程
  • Git 子模块 (Submodule) 完全使用指南
  • 烟花爆竹生产企业库房存储安全风险预警系统
  • 【Pandas】pandas DataFrame update
  • 【Docker基础】Docker容器管理:docker stop详解
  • Vue.js:渐进式框架赋能现代Web开发
  • 蓝桥杯嵌入式学习(cubemxkeil5)
  • word中如何快速打出上标?
  • 20250624java面试总结
  • 第九节 CSS工程化-预处理技术对比
  • 大白话蓝牙中的RPC:Remote Procedure Call远程过程调用
  • 壁挂马桶品牌推荐:我的“瑞尔特瑞家HX5”沉浸式体验报告健康与洁净的硬核科技
  • 从设备自动化到智能管控:MES如何赋能牛奶饮料行业高效生产?
  • 2025年渗透测试面试题总结-2025年HW(护网面试) 10(题目+回答)
  • Flask(四) 模板渲染render_template
  • 用Rust写平衡三进制加法器
  • 调试HDMI音频能8通道播放声音
  • 开疆智能CCLinkIE转ModbusTCP网关连接川崎机器人配置案例
  • linux grep的一些坑
  • GelSight Mini视触觉传感器开发资源升级:触觉3D点云+ROS2助力机器人科研与医疗等应用