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 关键字。