微信公众号: [大前端驿站]
关注大前端驿站。问题或建议,欢迎公众号留言。
这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战
定义
Generator 函数是 ECMAScript 6 新增的一个极为灵活的结构,拥有在一个函数块内暂停和恢复代码执行的能力。使用生成器可以自定义迭代器和实现协程。
函数名称前面加一个星号(*)表示它是一个生成器
function* generatorFnA() {}
function * generatorFnB() {}
function *generatorFnC() {}
复制代码
标识生成器函数的星号不受两侧空格的影响,上面三种方式都是合理的定义。
生成器对象一开始处于暂停执行(suspended)的状态。与迭代器相似,生成器对象也实现了 Iterator 接口,因此具有 next()方法。调用这个方法会让生成器开始或恢复执行
function* generatorFn() {}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
console.log(g.next); // f next() { [native code] }
复制代码
生成器函数只会在初次调用 next()方法后开始执行
function* generatorFn() {
console.log('foo');
}
// 初次调用生成器函数并不会打印日志
let generatorObject = generatorFn();
generatorObject.next(); // foo
复制代码
生成器对象实现了 Iterable 接口,它们默认的迭代器是自引用的
function* generatorFn() {}
const g = generatorFn();
console.log(g === g[Symbol.iterator]()) // true
复制代码
yield 表达式
yield 关键字可以让生成器停止和开始执行,也是生成器最有用的地方。生成器函数在遇到 yield关键字之前会正常执行。遇到这个关键字后,执行会停止,函数作用域的状态会被保留。停止执行的生成器函数只能通过在生成器对象上调用 next()方法来恢复执行
function* generatorFn() {
yield 'foo';
yield 'bar';
return 'baz';
}
let generatorObject = generatorFn();
console.log(generatorObject.next()); // { done: false, value: 'foo' }
console.log(generatorObject.next()); // { done: false, value: 'bar' }
console.log(generatorObject.next()); // { done: true, value: 'baz' }
复制代码
通过 yield 关键字退出的生成器函数会处在 done: false 状态;通过 return 关键字退出的生成器函数会处于 done: true 状态。
yield 关键字只能在生成器函数内部使用,用在其他地方会抛出错误。
可以使用星号增强 yield 的行为,让它能够迭代一个可迭代对象,从而一次产出一个值
function* generatorFn() {
yield* [1, 2, 3];
}
let g = generatorFn();
for (const x of g) {
console.log(x);
}
// 1
// 2
// 3
复制代码
提前终止生成器
return()和 throw()方法都可以用于强制生成器进入关闭状态
function* generatorFn() {}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
console.log(g.next); // f next() { [native code] }
console.log(g.return); // f return() { [native code] }
console.log(g.throw); // f throw() { [native code] }
复制代码
- return方式终止生成器
function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
console.log(g.return(4)); // { done: true, value: 4 }
console.log(g); // generatorFn {<closed>}
复制代码
生成器对象使用return()方法进入关闭状态后,就无法恢复了,如上所示,生成器是closed状态后再次调用next()方法后会显示为done:true状态
- throw方式终止生成器
function* generatorFn() {
for (const x of [1, 2, 3]) {
yield x;
}
}
const g = generatorFn();
console.log(g); // generatorFn {<suspended>}
try {
g.throw('foo');
} catch (e) {
console.log(e); // foo
}
console.log(g); // generatorFn {<closed>}
复制代码
throw()方法会在暂停的时候将一个提供的错误注入到生成器对象中。如果错误未被处理,生成器就会关闭.不过,假如生成器函数内部处理了这个错误,那么生成器就不会关闭,而且还可以恢复执行。错误处理会跳过对应的 yield,因此在这个例子中会跳过一个值
function* generatorFn() {
for (const x of [1, 2, 3]) {
try {
yield x;
} catch(e) {}
}
}
const g = generatorFn();
console.log(g.next()); // { done: false, value: 1}
g.throw('foo');
console.log(g.next()); // { done: false, value: 3}
复制代码
如果生成器对象还没有开始执行,那么调用 throw()抛出的错误不会在函数内部被捕获,因为这相当于在函数块外部抛出了错误。
~~ 感谢观看