ECMAScript 6中的Generator函数

 2015年08月01日    141     声明


Generator函数是ECMAScript 6中新增的特性,Generator是一种特殊的函数,是一个状态生成器,Generator函数可以管理内部状态的变化,并会对其内部定义的状态依次遍历,每被调用一次,就进入下一个内部状态。依靠Generator函数,可以有效解决JavaScript异步编程中的回调嵌套问题。

  1. Generator函数的定义
  2. yield关键字
  3. Generator函数中的方法


1. Generator函数的定义

定义一个Generator函数与定义一个普通函数类似,但有两点不同:一,function关键字与函数名之间要有一个*星号;二,函数内部使用yield关键字定义函数状态。

function * myGenerator() {
    yield 'status 1';
    yield 'status 2';
    return 'status 3';
}

Generator函数中,每个yield关键字定义一行语句,表示定义的一个状态。Generator函数执行时,会在每个yield关键字处暂停,调用next方法后,进入下一个状态。

在上面的示例代码中,共定义了3个状态,其执行结果如下:

var mg = myGenerator();
mg.next();  //{value: "status 1", done: false}
mg.next();  //{value: "status 2", done: false}
mg.next();  //{value: "status 3", done: true}
mg.next();  //{value: undefined, done: true}

每次调用Generator都会返回其内部状态,调用next方法,会返回一个包含valuedone两个属性的对象。其中,value属性表示当前的内部状态值,即:yield关键字后面后面定义的值;done属性是一个布尔值,表示状态遍历是否结束。


2. yield关键字

Generator函数是一个状态遍历器,每次调用next方法会进入下一个已定义的状态,yield关键字是暂停执行的标志。Generator函数状态遍历规则如下:

  1. yield是暂停标识,next方法遇到yield会暂停,并将其后的表达式返回(做为value值)
  2. 再次调用next方法,Generator函数继续执行,直到下一个yield执行暂停
  3. Generator函数在遇到return关键字或所有yield执行完毕后结束,即:done状态变为trueGenerator函数没有return语句或yield执行完毕,再次调用next方法,则返回的对象的value属性值为undefined


yield*语句与对象遍历

yield不同,yield*是一个对象遍历器,yield*会对其后的对象进行遍历,每调用一次next方法返回对象中的一个元素。

function * gen(){
  yield* ["a", "b", "c"];
}

var g = gen();

g.next();  // { value:"a", done:false }
g.next();  // { value:"b", done:false }
g.next();  // { value:"c", done:false }


3. Generator函数中的方法

next方法与参数传递

yield表达式默认没有返回值,但可以next方法传递参数,提供给下一个yield语句使用。

function * myGenerator() {
  yield 1+1;
  var arg = yield 2+2;
  var arg2 = yield arg;
  return arg2 + arg;
}

var mg = myGenerator();

mg.next();  // {value: 2, done: false}
mg.next();  // {value: 4, done: false}
mg.next(10);    // {value: 10, done: false}
console.log(mg.next(1));    // {value: 11, done: true}

在上面的示例中,第一次、第二次调用next方法时,方法没有传入参数,其返回值都是默认值,即:yield表达式的值。第三次、第四次调用时都分别传入了10、1两个值,函数内部arg、arg2分别用于接收next方法的传入参数。因此,其返回值都受传入参数的影响。


throw方法与异常捕获

Generator函数可以使用throw方法在函数外抛出异常,异常抛出后可以在Generator函数内部捕获异常。

function * myGenerator() {
  try {
    yield 'status 1';
    yield 'status 2';
    yield 'status 3';
  } catch(e) {
    console.log('Generator内捕获到异常:%s', e);
  }
}

var mg = myGenerator();
mg.next();
//{value: "status 1", done: false}
mg.throw('throw方法抛出异常');
// Generator内捕获到异常:throw方法抛出异常
// {value: undefined, done: true}
mg.next();
// {value: undefined, done: true}

throw方法抛出异常,异常可在Generator函数内部捕获,异常抛出后Generator函数执行完毕。