Generator函数

226 阅读2分钟

生成器GeneratorES6标准引人的新数据类型, 一个Generator看上去像一个函数, 但可以返回多次, 通过yield关键字, 将函数的执行流程挂起, 为改变函数执行流程提供了可能, 是一种异步编程解决方案

方法

  • Generator.prototype.next(): 返回一个由yield表达式生成的值
  • Generator.prototype.return(): 返回给定的值并结束生成器
  • Generator.prototype.throw(): 向生成器抛出一个错误

实例

使用function*声明方式会定义一个生成器函数generator function, 它返回一个Generator对象, 可以将Generator函数理解为一个状态机器, 封装了多个内部状态, 执行Generator函数会返回一个遍历器对象 调用一个生成器函数并不会马上执行它里面的语句, 而是返回一个生成器的迭代器iterator对象, 它是一个指向内部状态对象的指针. 当这个迭代器的next()方法后续被调用时, 其内部的语句会执行到第一个出现yield到位置为止, yield后紧跟迭代器要返回到值, 也就是指针会从函数头部或者上一次停下来的开始执行到下一个yield. 如果使用yield*, 则表示将执行权移交给另一个生成器函数(当前生成器暂停执行) next()方法返回一个对象, 这个对象包含两个属性: valuedone, value属性表示本次yield表达式的返回值, done属性为布尔类型, 表示生成器后续是还有yield语句, 即生成器函数是否已经执行完毕并返回

function* f(x) {
  yield x + 10;
  yield x + 20;
  yield x + 30;
}

const g = f(1);
console.log(g);		        // f {<suspended>}
console.log(g.next());		// {value: 11, done: false}
console.log(g.next());		// {value: 21, done: false}
console.log(g.next());		// {value: 31, done: true}
console.log(g.next());		// {value: undefined, done: true}

调用next()方法时, 如果传入了参数, 那么这个参数会传给上一条执行的yield语句左边的变量

function* f(x) {
  let y = yield x + 10;
  console.log(y);
  yield x + y;
  console.log(x, y);
  return x + 30;
}

const g = f(1);
console.log(g);				// f {<suspended}
console.log(g.next());			// {value: 11, done: false}
console.log(g.next(50));		// {value: 51, done: false}
console.log(g.next());			// {value: 31, done: true}
console.log(g.next());			// {value: undefined, done: true}

若显示指明return方法返回值, 则返回该值并结束遍历Generator函数, 若未显示指明return的值, 则返回undefined

function* f(x) {
  yield x + 10;
  yield x + 20;
  yield x + 30;
}

const g = f(1);
console.log(g);			        // f {<suspended>}
console.log(g.next());			// {value: 11, done: false}
console.log(g.next());			// {value: 21, done: false}
console.log(g.next());			// {value: 31, done: false}
console.log(g.next());			// {value: undefined, done: true}

yield*表达式表示yield返回一个遍历器对象, 用于在Generator函数内部, 调用另一个Generator函数

function* callee() {
  yield 100;
  yield 200;
  yield 300;
}
function* f(x) {
  yield x + 10;
  yield* callee();
  yield x + 30;
}

const g = f(1);
console.log(g);					// f {suspended}
console.log(g.next());				// {value: 11, done: false}
console.log(g.next());				// {value: 100, done: false}
console.log(g.next());				// {value: 200, done: false}
console.log(g.next());				// {value: 300, done: false}
console.log(g.next());                          // {value: 31, done: false}
console.log(g.next());				// {value: undefined, done: true}

异步操作的同步化表示

let it = null;

function f() {
  let rand = Math.random() * 2;
  setTimeout(function() {
    if(it) {
      it.next(rand);
    }
  }, 1000)
}
function success(r1, r2, r3) {
  console.log(r1, r2, r3);
}
// 成为线性任务而解决嵌套
function* g() {
  let r1 = yield f();
  console.log(r1);
  let r2 = yield f();
  console.log(r2);
  let r3 = yield f();
  console.log(r3);
  console.log(r3);
  success(r1, r2, r3);
}

it = g();
it.next();