Javascript中的Generator函数和yield关键字

在Javascript中,人人议论的最多的就是异步编程的操纵,怎样防止回调的屡次嵌套。异步操纵的回调一旦嵌套许多,不仅代码会变的痴肥,还很轻易失足。林林总总的异步编程解决方案也被不停提出,比方人人所熟知的Promise,co等等。本日所讲的Generator和yield就是和异步编程有关,能够协助我们把异步编程同步化。

Generator简介

Generator在情势上和函数差不多,只是在function和函数名之间多了一个*。Generator内部必需运用yield关键字。比方:

function * gen(){
  var result1 = yield 'hello';
  var result2 = yield 'world';
  return result1 + result2;
}

当挪用Generator函数时,并不会实行函数内部的代码,而是返回一个遍历器,该遍历器包括一个next要领。每次实行next要领,Generator函数体味最先实行,直到碰到yield语句,实行该语句并在此停息。用法以下:

var g = gen();
g.next(1);
//{value : 'hello', done : false}
g.next(2);
//{value : 'world', done : false}
g.next();
//{value : 3, done: true}
g.next();
//{value : undefined, done: true}

挪用next要领会返回一个对象,这个对象包括两个属性,value和done,value等于当前yield语句的值。done示意Generator函数体是不是被实行完。next要领同时接收一个参数,这个参数会作为yield语句的返回值,能够被背面的顺序所运用。当顺序实行完或许碰到return语句,value即为函数体的返回值,done就变成了true。至此,假如再实行next要领,value就为undefined, done依旧是true。

Generator在遍历中的运用

在js中,我们要遍历一个数组,我们能够用for…of如许的语句来举行遍历,这实在也是由于数组中包括了一个Generator遍历器。假如我们的本身定义的对象也包括一个遍历器,我们也就能够经由过程for…of等遍历语句来遍历自定义的对象。这个遍历器被存在Symbol.iterator属性中。

var myArray = {
  0: '你',
  1: '的',
  2: '名字',
  length: 3
};

myArray[Symbol.iterator] = function * (){
  for(var i = 0; i < this.length; i++) {
    yield this[i];
  }
};

for(var item of myArray) {
  console.log(item);
}
//你
//的
//名字

Generator在异步编程中的运用

Javascript的中心就是异步编程,每一个异步操纵都邑供应一个callback回调函数来返回实行的效果。假定我们有几个操纵,后一个操纵依靠前一个操纵的效果,假如采用回调的体式格局:

step1(function(value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3)) {
      //some code
    }
  });
})

如许的代码一单回调的嵌套变多,会让顺序变的异常难明白,同时也很轻易失足。我们要做的就是将回调变的扁平化。Promise对象就是如许的功用,将上述的操纵Promise化:

step1().then(function(value1){
  return step2(value1);
}).then(function(value2){
  return step3(value2);
}).then(function(){
  //some code
})

我们能够看到嵌套变少了,然则这并非最理想的解决方案,假如我们能将异步操纵变成同步操纵那样,即没了嵌套,顺序也会变的好明白。Generator函数就给我们供应的如许的时机。

function *workflow(){
  var value1 = yield step1();
  var value2 = yield step2();
  var value3 = yield step3();
  //some code
}

如许就是我们愿望效果,异步编程编程了同步编程的情势。我们接下来要做的是让这个Generator实行起来,所以我们须要一个实行器。co就是一个实行器,让Generator自动实行。

co(function *workflow(){
  var value1 = yield step1();
  var value2 = yield step2();
  var value3 = yield step3();
  //some code
});

co有个限定,yield语句背面跟的只能是Promise对象或许Thunk函数,关于co更细致的引见,能够参考阮先生的文章co 函数库的寄义和用法。但是如许的要领依旧须要依靠外在的库函数,因而ES6中提出了async和await关键字。async和await实在就是Generator的语法糖。只是它自带实行器。将上面的代码改写成async情势:

async function workflow(){
  var value1 = await step1();
  var value2 = await step2();
  var value3 = await step3();
  //some code
}

var result = workflow();

async没有了co的限定。await关键字背面能够跟 Promise 对象和原始范例的值(数值、字符串和布尔值,但这时候等同于同步操纵)。

    原文作者:leeif
    原文地址: https://segmentfault.com/a/1190000007475290
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞