17370845950

Javascript的生成器函数是什么_如何用于异步编程?
生成器函数是用 function* 声明的特殊函数,调用后返回迭代器对象,通过 next() 暂停/恢复执行并 yield 值;可配合 Promise 和执行器模拟 async/await 风格异步流程,但现已被原生 async/await 取代,多用于自定义迭代或框架底层(如 Redux-Saga)。

生成器函数是 JavaScript 中一种特殊的函数,它能暂停和恢复执行,配合 yield 关键字产出值。它本身不直接处理异步,但通过与 Promise、async/await 或自定义执行器协作,可构建出类似同步风格的异步流程。

生成器函数的基本特征

function* 声明,调用后返回一个迭代器对象(不是执行函数体),每次调用 next() 才运行到下一个 yield 并暂停。返回值是 { value, done } 形式的对象。

例如:

function* countdown(n) {
  while (n > 0) {
    yield n;
    n--;
  }
}

const it = countdown(3);
it.next(); // { value: 3, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 1, done: false }
it.next(); // { value: undefined, done: true }

用生成器模拟 async/await 风格的异步流程

核心思路是:让生成器 yield 一个 Promise,外部执行器捕获该 Promise,等它 resolve 后再用 next(value) 把结果传回生成器继续执行。

  • 生成器内部写法接近同步:不用嵌套 .then,也不显式写 await(但语义类似)
  • 需要手动或借助库(如 co)驱动执行,即反复调用 next() 并处理 Promise
  • 错误可通过 it.throw(err) 注入生成器内部,配合 try/catch 捕获

简易执行器示例:

function run(genFn) {
  const it = genFn();
  function next(val) {
    const { value, done } = it.next(val);
    if (done) return value;
    if (value instanceof Promise) {
      return value.then(next).catch(err => it.throw(err));
    } else {
      return next(value);
    }
  }
  return next();
}

// 使用:
run(function* () {
  const user = yield fetch('/api/user').then(r => r.json());
  console.log(user.name);
  const posts = yield fetch(`/api/posts?uid=${user.id}`).then(r => r.json());
  return posts;
});

与现代 async/await 的关系

生成器曾是实现协程式异步的主流方案(尤其在 async/await 出现前),但现在已被原生 async/await 取代:

  • async/await 语法更简洁,错误处理更自然,引擎级优化更好
  • 生成器现在更多用于需精细控制迭代逻辑的场景(如惰性序列、状态机、遍历树结构)
  • 少数库仍基于生成器实现高级控制流(如 Redux-Saga 中的 takeEverycall 等 effect)

实际建议

日常开发中无需主动用生成器写异步逻辑:

  • 优先使用 async/await —— 语义清晰、调试友好、浏览器支持完善
  • 理解生成器原理有助于读懂老项目或特定框架(如 Saga)的源码
  • 若需自定义迭代行为(比如分页拉取、无限滚动的数据流),生成器 + yield 是天然选择