JavaScript 生成器:为你的代码提供“暂停”按钮

发布: (2025年12月2日 GMT+8 07:47)
5 min read
原文: Dev.to

Source: Dev.to

介绍

如果你了解标准的 JavaScript 函数,你一定知道 run‑to‑completion 规则:一旦普通函数开始执行,在遇到 return 语句或代码块结束之前,任何事情都无法中止它。生成器打破了这条规则。

生成器是可以在执行过程中 暂停 的函数,允许其他代码运行,然后再从暂停的地方继续执行,并且记住所有变量。可以把普通函数想象成必须坐到终点的过山车,而生成器更像 Netflix 连续剧——你可以看一点,暂停去做别的事,然后再从同一位置继续观看。

定义生成器

使用两种特殊语法:

  • function* – 星号告诉 JavaScript 这是一个生成器。
  • yield – “暂停”按钮。
function* myGenerator() {
  console.log("1. Starting...");
  yield "First Pause"; // Pauses here and outputs "First Pause"

  console.log("2. Resuming...");
  yield "Second Pause"; // Pauses here and outputs "Second Pause"

  console.log("3. Finishing!");
  return "Done";
}

创建并运行生成器

调用生成器函数 不会 执行其代码;它返回一个 生成器对象(迭代器),相当于遥控器。

const gen = myGenerator(); // No console logs happen here!

要开始执行,调用生成器对象的 .next()。每次调用会运行代码直到下一个 yield(或 return),并返回一个对象:

  • valueyield 后面的内容。
  • done – 当生成器还能继续时为 false,完成时为 true
console.log(gen.next());
// Output:
// "1. Starting..."
// { value: "First Pause", done: false }

console.log(gen.next());
// Output:
// "2. Resuming..."
// { value: "Second Pause", done: false }

console.log(gen.next());
// Output:
// "3. Finishing!"
// { value: "Done", done: true }

向生成器发送数据

yield 也可以接收数据。当你调用 .next(value) 时,提供的 value 成为暂停的 yield 表达式的结果。

function* chattyGenerator() {
  const name = yield "What is your name?";
  const age = yield "How old are you?";
  return `Hello ${name}, you are ${age}!`;
}

const gen2 = chattyGenerator();

console.log(gen2.next().value);          // "What is your name?"
console.log(gen2.next("John").value);    // "How old are you?"
console.log(gen2.next(30).value);        // "Hello John, you are 30!"

惰性(按需)数据生成

生成器非常适合生成可能无限的序列,而不会耗尽内存。

function* idGenerator() {
  let id = 1;
  while (true) {
    yield id;
    id++;
  }
}

const ids = idGenerator();

console.log(ids.next().value); // 1
console.log(ids.next().value); // 2
console.log(ids.next().value); // 3

委托给另一个生成器 (yield*)

yield* 将控制权转交给另一个生成器,实现组合。

function* guestDJ() {
  yield "Song A";
  yield "Song B";
}

function* mainDJ() {
  yield "Intro";
  yield* guestDJ(); // Hand over control until guestDJ finishes
  yield "Outro";
}

for (const song of mainDJ()) {
  console.log(song);
}

// Output:
// Intro
// Song A
// Song B
// Outro

生成器与异步代码

async/await 出现之前,像 Redux‑Saga 这样的库使用生成器来处理异步流程。如果生成器 yield 一个 Promise,运行器会暂停执行,直到该 promise 解析。

function* fetchUser() {
  // Yield the promise; the runner waits for it to resolve.
  const user = yield fetch('/api/user');

  // The resolved value is passed back into the generator.
  console.log(user.name);
}

概念上,function* 类似于 async function,而 yield 的行为类似于 await

总结 – 生成器速查表

语法含义
function*声明一个生成器函数
yield value暂停执行并输出 value
const x = yield暂停并等待通过 .next() 传入的数据
generator.next()运行代码直到下一个 yield(或 return
yield* otherGenerator()委托给另一个生成器

生成器让你能够手动控制代码中的时间流。虽然 async/await 已经在大多数简单的数据获取场景中取代了它们,但生成器在处理复杂流程、无限数据流以及状态机实现时仍然非常强大。

Back to Blog

相关文章

阅读更多 »