# 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函数gthis对象上面添加了一个属性a,但是obj对象拿不到这个属性。
  • Generator函数也不能跟new一起使用。

# async函数

  • Generator函数的语法糖,async相当于*,await相当于yield
  • (1)async函数自带执行器,跟普通函数一模一样,不像generator需要调用next方法。
  • (2) 语义更加清楚,async表示函数里有异步操作,await表示等待后面的表达式的结果
  • (3)await后面可以是Promise对象或者原始类型的值,但此时都会转成立即执行resolvedPromise对象。
  • (4)返回Promise对象,用then指定下一步操作。
最后一次修改时间: 9/28/2020, 11:37:23 AM