intro
ES6引入了Generator
函数,可以通过yield
关键字,把函数的执行流挂起,
这为改变执行流程提供了可能,从而为异步编程提供解决方案。
API
function* foo() {...};
// 定义生成器函数generator function
。
f = foo()
获取Generator
对象,foo
为Generator
函数。
g.next(?v)
程序向后执行,返回下一个由yield
表达式生成的值。(对象格式:{value: xxx, done: false}
)。
直到得到包含return
值的对象{value: 返回值, done: true}
。或遇到异常。Uncaught xxx
。
next()
操作到return
语句或抛出异常语句会被终止。
参数v
可以设置上一条yield
语句的返回值。
yield
语句的返回值默认值undefined
。
g.return(?v)
直接结束生成器。返回对象{value: v, done: true}
。参数v
不传则为undefined
。
g.throw(?e)
向生成器抛出一个错误。
刚定义f
和每次调用f.next()
后,f状态为foo {<suspend>}
。
生成器终止后,状态为foo {<closed>}
。
demo
-
next()
基本用法function* foo() { console.log(1); yield 2; console.log(3); yield 4; console.log(5); return 6; console.log(7); yield 8; } f = foo(); Object.prototype.toString.apply(f) // "[object Generator]" f.next(); // 1 // {value: 2, done: false} f.next(); // 3 // {value: 4, done: false} f.next(); // 这次会遇到return语句。生成器终止。 // 5 // {value: 6, done: true} f.next(); // 这次不会打印7。函数已经return过,不会执行之后的语句。返回的对象也没有value。 // {value: undefined, done: true}
-
next(?value)
的参数function* foo() { var one = yield 1; var two = yield 2; var three = yield 3; console.log(one, two, three); return 666; } f = foo(); f.next(); // 执行到第一个yield语句。 // {value: 1, done: false} f.next(12); // 执行到第2个yield语句,并设置第1个yield表达式的返回值one为指定值。 // {value: 2, done: false} f.next(); // 执行到第3个yield,并设置two为undefined。 // {value: 3, done: false} f.next(56); // 这次是返回值。并设置three为56。 // 12 undefined 56 // {value: 666, done: false}
-
return(?value)
的参数
f.return()
会直接终止生成器,返回的对象为{value: undefined, done: true}
f.return(v)
不同的是,返回的对象的value
属性为指定值v
,即{value: v, done: true}
。
yield
和yield*
yield
关键字用于暂停和恢复一个生成器函数generator function
(function*
或遗留的生成器函数)。
[rv] = yield [expression];
yield*
表达式用于委托给另一个generator
|可迭代对象。
yield* [[expression]];
function* foo() {
yield 1;
yield 2;
return 333;
}
function* bar() {
yield* [1, 2]
return 333;
}
f = foo();
b = bar();
// 之后f和b的使用相同。
yield*
表达式表示yield
返回一个遍历器对象,用于在generator function
内部,调用另一个generator function
。
应用
- 实现
Iterator
,(用for..of
)遍历对象。function* objEntries(obj) { let keys = Reflect.ownKeys(obj); for (let key of keys) { yield [key, obj[key]]; } } var boy = {name: "JT", age: 20}; var entries = objEntries(boy); for (let e of entries) { console.log(e); } // (2) ["name", "JT"] // (2) ["age", 20] var entries = objEntries(boy); for (let [prop, value] of entries) { console.log(`${prop} = ${value}`); } // name = JT // age = 20
object
不具备Iterator
接口,无法用for..of
遍历。
不过可以用generator function
加上Iterator
接口,然后可以用for..of
遍历。