JavaScript yield 关键字
最后修改于 2025 年 4 月 16 日
在本文中,我们将展示如何在 JavaScript 中使用带有 yield 关键字的生成器函数。
yield 关键字
yield 关键字用于在生成器函数中暂停执行并返回值。当生成器恢复时,执行将从暂停的位置继续。这允许迭代值的产生。
生成器函数使用 function* 语法声明。它们返回一个可迭代的生成器对象。 yield 关键字是使生成器与常规函数不同的关键。
生成器在执行之间保持其状态。这使得复杂的迭代和惰性求值成为可能。它们对于有效处理大型数据集或无限序列非常有用。
基本生成器函数
此示例演示了 yield 在生成器中的最简单用法。
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = simpleGenerator();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
生成器按顺序产生三个值。每次调用 next() 都会恢复执行,直到下一个 yield。生成器会记住它在调用之间的状态。
$ node main.js 1 2 3
具有无限序列的生成器
生成器可以生成无限序列而无需消耗内存。
function* infiniteSequence() {
let i = 0;
while (true) {
yield i++;
}
}
const gen = infiniteSequence();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
此生成器生成一个无限的数字序列。它不会一次将所有值存储在内存中。每个值都是在需要时通过调用 next() 生成的。
$ node main.js 0 1 2
将值传递给 yield
值可以通过 next() 方法传递到生成器中。
function* generatorWithInput() {
const name = yield 'What is your name?';
const age = yield `Hello ${name}, how old are you?`;
yield `${name} is ${age} years old`;
}
const gen = generatorWithInput();
console.log(gen.next().value);
console.log(gen.next('John').value);
console.log(gen.next(30).value);
生成器首先产生一个问题。传递给 next() 的值成为 yield 表达式的结果。这使得生成器和调用者之间能够进行双向通信。
$ node main.js What is your name? Hello John, how old are you? John is 30 years old
使用 yield* 进行委托
yield* 表达式委托给另一个生成器。
function* innerGenerator() {
yield 'a';
yield 'b';
}
function* outerGenerator() {
yield 1;
yield* innerGenerator();
yield 2;
}
const gen = outerGenerator();
for (const val of gen) {
console.log(val);
}
yield* 表达式产生来自 innerGenerator 的所有值。这类似于展开内部生成器的值。它提供了一种组合生成器的方法。
$ node main.js 1 a b 2
生成器中的早期返回
生成器可以使用 return 返回最终值。
function* generatorWithReturn() {
yield 'First';
yield 'Second';
return 'Done';
yield 'This will not execute';
}
const gen = generatorWithReturn();
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
return 语句结束生成器。后续的 next() 调用返回 {value: undefined, done: true}。返回值出现在 done 变为 true 之前的最后一个 next() 调用中。
$ node main.js
{ value: 'First', done: false }
{ value: 'Second', done: false }
{ value: 'Done', done: true }
{ value: undefined, done: true }
生成器中的错误处理
生成器可以使用 try-catch 块处理错误。
function* errorHandlingGenerator() {
try {
yield 'Start';
throw new Error('Something went wrong');
yield 'This will not execute';
} catch (err) {
yield `Caught error: ${err.message}`;
}
yield 'End';
}
const gen = errorHandlingGenerator();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);
在生成器内部抛出的错误可以在生成器内部被捕获。生成器在 catch 块之后继续执行。这允许在异步操作中进行可靠的错误处理。
$ node main.js Start Caught error: Something went wrong End
实际用例:分页
生成器对于实现分页很有用。
function* paginate(items, pageSize) {
for (let i = 0; i < items.length; i += pageSize) {
yield items.slice(i, i + pageSize);
}
}
const items = Array.from({length: 10}, (_, i) => i + 1);
const pages = paginate(items, 3);
for (const page of pages) {
console.log('Page:', page);
}
此生成器产生来自数组的项目页面。每次调用 next() 都会返回下一页。这种模式对于大型数据集来说是内存效率的。
$ node main.js Page: [ 1, 2, 3 ] Page: [ 4, 5, 6 ] Page: [ 7, 8, 9 ] Page: [ 10 ]
来源
在本文中,我们已经演示了如何在 JavaScript 的生成器函数中使用 yield 关键字。