ES6学习——生成器(Generators):return和throw

73 篇文章 23 订阅

return和throw在生成器中起到了终止的作用,生成器原型那篇文章里介绍了Chrome浏览器只实现了throw,没有实现return。所以我们先看看throw是怎么用:

function *foo() {
	yield 1;
	yield 2;
	yield 3;
}
var it = foo();
console.log(it.next()); // { value: 1, done: false }
try {
	it.throw( new Error("Oops!") );
}
catch (err) {
	console.log(err); // Error: Oops!
}
console.log(it.next()); // { value: undefined, done: true }


迭代器it可以直接调用throw方法,传入的参数就是catch中的err,然后在调用it的next方法时,done已经被设置成true了,就是说生成器终止了。这个异常其实是在生成器内部产生的,只是我们没有捕获,所以继续往外抛了出来,如果在内部try-catch这个异常也是可以的:

function* genFunc1() {
	try {
		console.log('Started');
		yield 1; 
                yield 2;
	} catch (error) {
		console.log('Caught: ' + error);
	}
}

let genObj1 = genFunc1();
console.log(genObj1.next());//Object {value: 1, done: false}

genObj1.throw(new Error('Problem!'))
genObj1.next();//Object {value: undefined, done: true}

 

假如我们不捕获异常会怎么样:

function* genFunc1() {
		console.log('Started');
		yield 1; 
		yield 2;
}

let genObj1 = genFunc1();
console.log(genObj1.next());

genObj1.throw(new Error('Problem!'))//这里直接抛出异常
console.log(genObj1.next());//这里不再执行

最后看个更详细的例子:

function *foo() {
	try {
		yield 1;
	}
	catch (err) {//catch异常的yield,下面的yield还可以继续执行
		console.log( err );
	}
	yield 2;
	
	throw "Hello!";
}

var it = foo();
it.next(); // { value: 1, done: false }
try {
	it.throw( "Hi!" ); // Hi!
	// { value: 2, done: false }
	it.next();
	console.log( "never gets here" );
}
catch (err) {
	console.log( err ); // Hello!
}


由于Chrome中没有实现return,我们可以自己简单实现一下,return的语义就是终结生成器,done设置成true,value设置成return传入的参数值。

let Generator_prototype = Object.getPrototypeOf(function* (){}).prototype;
Generator_prototype.return = function (val) { 
	[...this];//spread操作符让生成器执行完
	return {value:val,done:true};
};

function* genFunc1() {
	try {
		console.log('Started');
		yield 1;
		yield 2;
	} finally {
		console.log('Exiting');
	}
}

let genObj1 = genFunc1();
console.log(genObj1.next());
console.log(genObj1.return('Result'));
console.log(genObj1.next());

/*
Started
Object {value: 1, done: false}
Exiting
Object {value: "Result", done: true}
Object {value: undefined, done: true}
*/



但是上面这种简单实现有个严重的问题就是不能处理无限的生成器,例如:

function* genFunc(){
    for(let i=0;;i++){
        yield i;
    }
}
//如果调用return会导致浏览器崩溃


还有一种问题不能处理:

function* genFunc2() {
    try {
        console.log('Started');
        yield;
    } finally {
        yield 'Not done, yet!';
    }
}
上面这种写法,调用return时应该是不终止生成器,在下一次调用next的时候在终止。但上面在finally里写yield的做法十分不推荐,本身finally的意思就是在终止之前进行最后的处理,finally是最后一步。但是把yield放在里面导致了生成器不能结束,finally也失去了其意义。

我还没有想到一个完美的解决方法处理上面的问题,有兴趣的同学可以自己想想。


*以上全部代码在Chrome 48下通过测试

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值