# Generator 函数
# 简介
Generator函数是 ES6 提供的一种异步编程解决方案。- 语法上,
Generator函数是一个状态机,封装了多个内部状态。 - 执行
Generator函数会返回一个遍历器对象,即Generator函数既是状态机,也是一个遍历器对象生成函数。 - 形式上,
Generator是一个普通函数,但有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式(意思“产出”)。
function* helloGenerator () {
yield 'hello';
yield 'world';
return 'end';
}
var hg = helloGenerator()
- 调用
Generator函数后,函数并不会执行,而只是返回一个指向内部状态的指针对象,即遍历器对象。
hg.next()
// { value: 'hello', done: false }
hg.next()
// { value: 'world', done: false }
hg.next()
// { value: 'end', done: false }
hg.next()
// { value: undefined, done: false }
- 调用
next方法,使得指针移向下一个状态,而yield表达式是暂停执行的标记。
# yield 表达式
yield表达式后面的值作为返回对象的value的值。- 遇到
return,则其后面的值作为返回对象的value的值,之后再调用next则就是undefined。
# 与 Iterator 接口的关系
function* gen() {
// to do something
}
var g = gen()
g[Symbol.iterator]() == g
// true
- 上面代码中,
gen是一个Generator函数,调用它会生成一个遍历器对象g。它的Symbol.iterator属性,也是一个遍历器对象生成器,执行它会返回它自己(遍历器对象g)。
# next 方法的参数
yield表达式本身没有返回值,next可带一参数,当作上一个yield的返回值。
function* gen() {
var r = yield 2
var t = r * 3
return t
}
var g = gen()
g.next()
// { value: 2, done: false }
g.next(3)
// { value: 9, done: true }
# for...of循环
- return 语句的值并不会被遍历出来。同时 扩展运算符(...)、结构赋值和
Array.from方法内部调用的,都是遍历器接口。如下
function* numbers() {
yield 1
yield 2
yield 3
return 4
}
for(let key of numbers()) {
console.log(key)
}
// 1 2 3
[...numbers]
// [1, 2, 3]
let [x, y, z] = numbers()
// x: 1
// y: 2
// z: 3
Array.from(numbers())
// [1, 2, 3]
# Generator.prototype.throw() 抛出错误
var gen = function* gen(){
try {
yield console.log('a');
} catch (e) {
// ...
}
yield console.log('b');
yield console.log('c');
}
var g = gen();
g.next() // a
g.throw() // b
g.next() // c
- 首先必须先执行一次
next,之后抛错才能被内部捕获,因为第一次执行next等同于启动执行Generator函数的内部代码。 g.throw()执行后悔附带执行一条yield表达式g.throw()执行若内部没有去try..catch捕获,那么它将会把错误信息抛到函数外。g.throw(e)可以带一参数,该参数会在try...catch那被传出。
# Generator.prototype.return()
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next()
// { value: 1, done: false }
g.return('foo')
// { value: 'foo', done: false }
g.next()
// { value: undefined, done: false }
return方法,可以返回指定的值,并终结遍历器Generator函数,之后调用next方法的value值都返回undefined。
# yield* 表达式
function* bar() {
yield 'x';
yield* foo();
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
yield 'a';
yield 'b';
yield 'y';
}
// 等同于
function* bar() {
yield 'x';
for (let v of foo()) {
yield v;
}
yield 'y';
}
for (let v of bar()){
console.log(v);
}
// "x"
// "a"
// "b"
// "y"
# Generator 函数的this
function* g() {}
g.prototype.hello = function () {
return 'hi!';
};
let obj = g();
obj instanceof g // true
obj.hello() // 'hi!'
Generator函数g返回的遍历器obj,是g的实例,而且继承了g.prototype.
function* g() {
this.a = 11;
}
let obj = g();
obj.next();
obj.a // undefined
Generator函数g在this对象上面添加了一个属性a,但是obj对象拿不到这个属性。Generator函数也不能跟new一起使用。
# async函数
- 是
Generator函数的语法糖,async相当于*,await相当于yield。 - (1)
async函数自带执行器,跟普通函数一模一样,不像generator需要调用next方法。 - (2) 语义更加清楚,
async表示函数里有异步操作,await表示等待后面的表达式的结果 - (3)
await后面可以是Promise对象或者原始类型的值,但此时都会转成立即执行resolved的Promise对象。 - (4)返回
Promise对象,用then指定下一步操作。
← Promise 对象 Proxy 对象 →