生成器
函数暂停然后再次恢复的能力,不是异步函数所独有的。 JavaScript 也有一个称为生成器函数的特性。 这些都是相似的,但没有Promise
。
当用function*
定义一个函数(在函数后面加星号)时,它就成为一个生成器。 当你调用一个生成器时,它将返回一个迭代器,我们在第 6 章已经看到了它。
function* powers(n) {
for (let current = n;; current *= n) {
yield current;
}
}
for (let power of powers(3)) {
if (power > 50) break;
console.log(power);
}
// → 3
// → 9
// → 27
最初,当你调用powers
时,函数在开头被冻结。 每次在迭代器上调用next
时,函数都会运行,直到它碰到yield
表达式,该表达式会暂停它,并使得产生的值成为由迭代器产生的下一个值。 当函数返回时(示例中的那个永远不会),迭代器就结束了。
使用生成器函数时,编写迭代器通常要容易得多。 可以用这个生成器编写group
类的迭代器(来自第 6 章的练习):
Group.prototype[Symbol.iterator] = function*() {
for (let i = 0; i < this.members.length; i++) {
yield this.members[i];
}
};
不再需要创建一个对象来保存迭代状态 - 生成器每次yield
时都会自动保存其本地状态。
这样的yield
表达式可能仅仅直接出现在生成器函数本身中,而不是在你定义的内部函数中。 生成器在返回(yield
)时保存的状态,只是它的本地环境和它yield
的位置。
异步函数是一种特殊的生成器。 它在调用时会产生一个Promise
,当它返回(完成)时被解析,并在抛出异常时被拒绝。 每当它yield
(await
)一个Promise
时,该Promise
的结果(值或抛出的异常)就是await
表达式的结果。