Generator 函数实现 async/await 异步控制流

在 JavaScript 中,Generator 函数可以配合 yield 关键字实现类似 async/await 的异步控制流。以下是详细解释和实现步骤:

核心原理

  1. Generator 特性:可以暂停执行(yield)和恢复执行(next()
  2. 异步处理:当遇到异步操作时暂停执行,操作完成后再恢复
  3. 自动执行:需要一个执行器(runner)来管理 Generator 的流程

实现步骤(含完整代码)

// 1. 定义异步执行器
function runGenerator(genFunc) {
  const generator = genFunc();
  
  function handle(result) {
    if (result.done) return result.value;
    
    return Promise.resolve(result.value)
      .then(res => handle(generator.next(res)))  // 成功时恢复执行
      .catch(err => handle(generator.throw(err))); // 错误时抛出异常
  }
  
  try {
    return handle(generator.next());
  } catch (err) {
    return Promise.reject(err);
  }
}

// 2. 创建模拟异步函数
function fetchData(url, delay) {
  return new Promise(resolve => {
    setTimeout(() => resolve(`来自 ${url} 的数据`), delay);
  });
}

// 3. 使用 Generator 定义异步流程
function* main() {
  try {
    console.log("开始请求");
    
    // yield 暂停执行,等待 Promise 完成
    const data1 = yield fetchData("https://api.example.com/users", 1000);
    console.log("收到数据1:", data1);
    
    const data2 = yield fetchData("https://api.example.com/posts", 800);
    console.log("收到数据2:", data2);
    
    return "所有操作完成!";
  } catch (error) {
    console.error("捕获错误:", error);
    return "处理错误";
  }
}

// 4. 执行异步流程
runGenerator(main)
  .then(finalResult => console.log("最终结果:", finalResult))
  .catch(err => console.error("未处理的错误:", err));

执行流程解析:

  1. 初始化

    • runGenerator(main) 创建生成器对象
    • 首次调用 generator.next() 启动生成器
  2. 首次异步操作

    • 遇到 yield fetchData(...) 暂停执行
    • 执行器等待 Promise 完成
    • 1秒后 Promise 完成,将结果传给 generator.next(res)
  3. 恢复执行

    • 生成器从暂停点继续
    • data1 获得异步结果
    • 执行到下一个 yield 再次暂停
  4. 后续操作

    • 重复上述过程直到所有 yield 完成
    • 最终返回 return 的值
  5. 错误处理

    • 如果任何 Promise 被拒绝(reject)
    • 执行器调用 generator.throw(err)
    • 在生成器中被 try/catch 捕获

关键优势:

  1. 同步化写法:用同步代码风格写异步逻辑
  2. 流程控制:轻松实现顺序执行(无需回调嵌套)
  3. 错误处理:使用 try/catch 统一处理错误

实际输出示例:

开始请求
(等待1秒...)
收到数据1: 来自 https://api.example.com/users 的数据
(等待0.8秒...)
收到数据2: 来自 https://api.example.com/posts 的数据
最终结果: 所有操作完成!

对比 async/await:

// 等效的 async/await 实现
async function mainAsync() {
  const data1 = await fetchData("https://api.example.com/users", 1000);
  const data2 = await fetchData("https://api.example.com/posts", 800);
  return "所有操作完成!";
}

Generator 方案本质上实现了 async/await 的底层机制,但需要手动管理执行流程。

适用场景:

  1. 需要兼容不支持 async/await 的老环境
  2. 需要更精细控制异步流程(如中间暂停)
  3. 实现自定义高级异步模式(如取消操作)

注意:现代 JavaScript 中应优先使用 async/await,但理解 Generator 实现原理有助于深入掌握异步编程模型。

posted @ 2025-07-01 09:39  张浩伟  阅读(44)  评论(0)    收藏  举报