生成器
基础
- 生成器拥有在一个函数块内暂停和恢复代码执行的能力。
- 创建生成器:
//标识生成器函数的星号不受两侧空格的影响 function* generator(){ ... }
- 注意:箭头函数不能用来定义生成器函数
- 调用生成器函数会产生一个生成器对象,生成器对象一开始处于暂停执行状态,与迭代器相似,生成器对象也实现了iterator接口,具有next()方法,调用next()方法可以让生成器开始或恢复执行
yield
- yield关键字可以让生成器停止和开始执行,生成器在遇到yield关键字之前会正常执行,遇到这个关键字后会停止,函数作用域的状态会保留,停止的生成器函数只能通过调用next()方法来恢复执行
- yield关键字只能在生成器内部使用,用在其他地方会抛出错误
// 无效 function* generator(){ function a(){ yield; } }
实现输入和输出
- 上一次让生成器函数暂停的yield关键字会接收到传给next()方法的第一个值
function* generator(initial) { console.log(initial); console.log(yield); console.log(yield); } let generatorObj = generator('foo'); generatorObj.next('bar'); //foo 第一次传入的值不会被调用,是因为第一次 next()是为了执行生成器函数 generatorObj.next('test'); //test generatorObj.next('new'); //new
- 同时用于输入和输出
function* generator() { return yield 'test'; } let generatorObj = generator(); console.log(generatorObj.next()); //value: 'test', done: 'false' console.log(generatorObj.next('new')); //value: 'new', done: 'true'
产生可迭代对象
使用星号增强yield的行为,让他能够迭代一个可迭代对象,从而一次产出一个值
function* generator() {
yield*[1, 2, 3];
}
for (const x of generator()) {
console.log(x);
}
提前终止生成器
return()和throw()方法都可以用于强制生成器进入关闭状态
-
return():通过它进入关闭状态后就无法恢复,后续调用next()会显示done:true状态,提供的任何返回值都不会被存储或传播
function* generator() { for (const x of [1, 2, 3]) { yield x; } } const g = generator(); console.log(g.next()); // { value: 1, done: false } console.log(g.return(10)); // { value: 10, done: true } console.log(g.next()); // { value: undefined, done: true } console.log(g.next()); // { value: undefined, done: true }
-
throw():会在暂停的时候将一个提供的错误注入到生成器对象中,若错误未被处理,生成器就会关闭;若生成器函数内部处理了这个错误,生成器就不会关闭,还可以恢复执行,错误处理会跳过对应的yield
function* generator() { for (const x of [1, 2, 3]) { yield x; } } const g = generator(); console.log(g); // generator {<suspended>} try { g.throw('error'); } catch (e) { console.log(e); // error } console.log(g); // generator {<closed>}
function* generator() { for (const x of [1, 2, 3]) { try{ yield x; }catch(e){} } } const g = generator(); console.log(g.next()); // { value: 1, done: false } g.throw('error'); console.log(g.next()); // { value: 3, done: false }