[JS] generator基本使用
next方法与yield关键字
generator函数可以返回一个迭代器,通过next
方法切换generator的状态。
generator函数被调用时并不会执行内部的语句,而是返回一个迭代器对象。
迭代器对象首次调用next
方法,才开始执行generator函数的语句。
直到遇到yield
语句,内部的执行中断,返回yield
关键字右侧表达式的值作为迭代器调用next
方法的返回值。
yield
语句本身没有返回值,由下一次调用next
方法时传入参数作为yield
的返回值。
function* gen(){
yield 'hello';
let msg = yield 'world';
console.log(msg);
yield 'end';
}
const g = gen();
console.log(g.next());
console.log(g.next());
console.log(g.next('passing msg'));
console.log(g.next());
输出结果:
{ value: 'hello', done: false }
{ value: 'world', done: false }
passing msg
{ value: 'end', done: false }
{ value: undefined, done: true }
throw方法
迭代器对象可以通过调用throw
方法向generator函数内部“抛出”异常,在函数内部通过try/catch捕获。
也可以在generator函数内部抛出异常,在调用迭代器方法的位置抛出异常。
向内部抛出异常 - 分类讨论:
- (理想情况)调用
iterator.throw(new Error(...))
向内部抛出异常,在内部对应的yield
表达式使用try/catch
捕获异常; - 如果函数内部没有捕获异常,那么在
iterator.throw()
语句所在的位置抛出异常; - 如果
generator
内部和iterator.throw
所在位置都没有捕获异常进行处理,那么程序终止; - 还没首次执行
next
就执行throw
,直接在外部调用iterator.throw
的位置抛出异常。
向外抛出异常
接下来先看一个向外抛出异常的案例代码:
function* gen(){
yield 1;
throw new Error('inner error');
yield 2; // 不会被执行
yield 3; // 不会被执行
}
const g = gen();
let res;
do{
try{
res = g.next();
console.log(res);
}catch(e){
console.log(e); // 捕获到 'inner error'
}
}while(!res.done);
运行结果:
{ value: 1, done: false }
Error: inner error
{ value: undefined, done: true }
解析:在generator内部使用throw关键字抛出异常,外部调用iterator.next
的地方捕获异常,由于generator抛出异常,JS引擎会认为这个generator已经运行结束了,后续的yield不会执行,迭代器的done
变为true
;
return关键字
没有写return
语句的 Generator 函数默认在尾部返回undefined
。
return
关键字会返回右侧表达式的值作为next
方法的返回值。
return
会终止generator,后续的代码都不会执行了,这个特点和普通函数保持一致。
function* gen(){
yield 1;
return 2;
yield 3;
}
const g = gen();
let res;
do{
res = g.next();
console.log(res.value);
}while(!res.done);
执行结果:
1
2
return 方法
generator函数返回的迭代器对象还有return
方法。
可以在外部手动得到return
方法得到的值,并且结束generator。
function* gen(){
yield 1;
yield 2;
yield 3;
}
const g = gen();
console.log(g.next());
console.log(g.return('done'));
console.log(g.next());
运行结果:
{ value: 1, done: false }
{ value: 'done', done: true }
{ value: undefined, done: true }
next、throw、return的共同点
这三个方法的本质是让generator函数恢复执行,并且使用不同的语句替换yield
表达式。
next()
将yield
表达式替换成一个值;throw()
将yield
表达式替换成一个throw
语句;return()
将yield
表达式替换成一个return
语句。