一个简单的生成器例子:
function* somewords() {
yield "hello";
yield "world";
}
for (var word of somewords()) {
alert(word);
}
每次调用.next()方法,会执行一次yield方法
如何关闭生成器:
先来了解生成器的特性
generator.return()
generator.next()的可选参数
generator.throw(error)
yield*
以前用过的方法:
function dothings() {
setup();
try {
// ... 做一些事情
} finally {
cleanup();
}
}
dothings();
其中cleanup()可以用来关闭连接或文件、释放资源,更新dom等操作。
生成器版本:
function* producevalues() {
setup();
try {
// ... 生成一些值
} finally {
cleanup();
}
}
for (var value of producevalues()) {
work(value);
}
ES6会为我们自动执行清理,在前面说过迭代器iterator接口只支持可选的.return()方法,当返回{done:true}会退出自动调用方法
生成器主导模式
生成器可以用来实现异步编程,完成你用异步回调或promise 链所做的一切,生成器的.next()方法接受一个可选参数,参数稍后会作为 yield 表达式的返回值出现在生成器中。那就是说, yield 语句与 return 语句不同,它是一个只有当生成器恢复时才会有值的表达式。
var results = yield getdataandlatte(request.areacode)
这个过程程序能够返回有用信息,并且可暂停任意时间的生成器,直到有人调用.next({data:..,coffee:...}),将获得变量存储到results并执行下一行代码:
function* handle(request) {
var results = yield getdataandlatte(request.areacode);
results.coffee.drink();
var target = mosturgentrecord(results.data);
yield updatestatus(target.id, "ready");
}
yield 仍然保持着它的原始含义:暂停生成器,返回值给调用者
普通函数则与之不同,通常更倾向于满足调用者的需求。可以扩展生成器:
function rungeneratoronce(g, result) {
var status = g.next(result);
if (status.done) {
return; // phew!
}
// 生成器请我们去获取一些东西并且
// 当我们搞定的时候再回调它
doasynchronousworkincludingespressomachineoperations(
status.value,
(error, nextresult) => rungeneratoronce(g, nextresult));
}
同时需要创建一个生成器并运行一次:
rungeneratoronce(handle(request), undefined);
生成器一般是生成Promise对象来告诉调用者要作的事情
如何销毁生成器
生成器的错误处理过程:如果出现错误不执行.next()而是转而执行.throw(error);生成器内部抛出的异常总是会传播到调用者。所以无论生成器是否捕获错误, generator.throw(error)都会抛出 error 并立即返回给你。
当生成器执行到一个 yield 表达式并暂停后可以实现以下功能:
- 调用 generator.next(value),生成器从离开的地方恢复执行。
- 调用 generator.return(),传递一个可选值,生成器只执行 finally 代码块并不再恢复执行。
- 调用 generator.throw(error),生成器表现得像是 yield 表达式调用一个函数并抛出错误。
- 或者什么也不做,生成器永远保持冻结状态
结合生成器实现更多功能
写一个简单的生成器函数联结两个可迭代对象
function* concat(iter1, iter2) {
for (var value of iter1) {
yield value;
}
for (var value of iter2) {
yield value;
}}
//ES6
function* concat(iter1, iter2) {
yield* iter1;
yield* iter2;
}
普通 yield 表达式只生成一个值,而 yield*表达式可以通过迭代器进行迭代生成所有的值。
可以使用yield*使用生成器调用生成器:
function* factoredoutchunkofcode() { ... }
function* refactoredfunction() {
...
yield* factoredoutchunkofcode();
...
}
本节参考《ES6-In-Depth》