ES6新特性:Generator以及衍生NPM库CO入门

2015年ES6的发布带来了一系列的JS新特性,Generator在其中属于一个比较重要的新特性,这里就详细地介绍一下。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();

以这个最基本的Generator为例,他和普通函数有以下两点区别:一个是使用了function*,有点类似于我们在强类型语言中常见的指针;另一个是在函数内部有Yield关键字。
yield的作用在于暂停函数,并且返回yield右边的值。

yield 1+1 //返回2
yield 1 == 1 //返回true

我们知道了yield的作用,那么它在Generator中是有通过什么方式使用的呢?

Generator在创建时不会执行函数(再一次类比于指针,就像是我们只创建了一个指向该函数的指针但是没有执行),只有我们使用了*.next()之后才会开始执行,并且在下一个yield处停止,参考以下例子

function* test(){
    console.log('hello'); 
    yield"i'm stopped");
    console.log('world');
}

var g = test();
var yield_value = g.next();//{value:'i'm stopped', done:false}
g.next();
  • 我们先是创建了一个test的实例,这时什么也没有发生
  • 然后我们调用了next()语句,输出hello,之后在yield暂停,并且返回i’m stopped;给yield_value
  • 接下来再次执行next()语句,输出world,程序结束(done参数表示函数是否已经执行完毕,这时的done为true)。

我们需要注意的是,yield返回了右边表达式的值,但是在函数内部将yield表达式直接赋值是不可行的,比如以下这个例子

function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
  • 我们想要的结果应该和没有yield一样的,可是就像上面显示的一样,next函数yield只会将右边表达式的值传递给next,但是不能够传递给左边的表达式。
  • 准确来说,yield会将next()里面的参数传递给左边的表达式。如果我们写成如下形式的话就可以让函数输出我们需要的结果了。
function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
var i = a.next();
i = a.next(i.value);
i = a.next(i.value);
console.log(i.value);

进阶玩法,在不清楚有多少个yield的情况下可以以这种方式解决

function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
var i = {value:0};
while (!(i = a.next(i.value)).done);
//不断保存之前yield的值再传递给下一个next直到函数结束(done为true)
console.log(i.value);//21
  • 注意,yield只能在generator,即有*号的函数中使用,普通函数中使用会出错
  • 在表达式中使用需要加上括号,不然会认为这是一个变量。

其他的应用方式可以参考ES6入门比较详细地介绍了各种属性和用法;但是我这里只是为了入门,一些高级技巧没有实际的使用场景的话很难记住,这里就不做介绍了。

Generator的功能

介绍完Generator,他到底有什么用呢?它作为ES6中协程的一个概念引进的。有了yield的帮助,我们可以自行定义语句执行顺序,协调好各个代码逻辑。我们这里使用它来解决同步编程中callback hell的问题,但是我们也要明白,generator不仅仅是解决callback而已,和promise相比,generator能够操控语句执行,顺带地解决了异步,而promise是专为同步而生的,他本质只是把callback hell转换成便于阅读的形式,而不是从根本改变代码的执行形式。
CO库使用Generator的特性来生成同步的函数。具体看下面的例子

co(function *(){
    var rs = yield db.query('select url from xxx');
    rs.forEach(rs){
        var content = yield getUrl(rs.url);
        ...
    }
})();

只要用CO将generator套起来,里面的代码不需要其他任何的改变,他就会使得代码等待yield右边表达式运行结束再继续,实现了同步编程又不需要改变代码结构。
有一些我们required的模块不支持同步,这时我们可以使用thunkify来转化一下使用

var thunkify = require('thunkify');
var fs = require('fs');
var read = thunkify(fs.readFile);
read('package.json', 'utf8')(function(err, str){

});

此外,对于GENERATOR我们还有一些扩展API的模块Yield可供我们使用
Yield

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值