ES6 生成器简朴应用

观点

生成器是由生成器函数( generator function )运转后获得的,是可迭代的。

function* gen() { 
  yield 'a';
  yield 'b';
  yield 'c';
}

let g = gen(); 
// "Generator { }"

道理及简朴应用

生成器有一个很大的特性,它能够停息内部代码运转,返回一个值给外部函数。(停息后不会阻挠其他代码运转)当外部挪用其 next 要领后,会继承实行剩下的代码,并接收外部传来的一个参数。这个完成重要依赖于症结字 yield

yield 症结字使生成器函数实行停息,
yield 症结字后面的表达式的值返回给生成器的挪用者。它能够被认为是一个基于生成器的版本的
return 症结字。

function* g(){
    var a = yield 2;
    console.log(a);
}

var it = g(); // 返回一个可迭代的生成器对象
console.log(it.next()); // 实行生成器函数内部代码,第一次返回 {done: false, value: 2}
it.next(3); // 继承实行生成器函数内部代码,同时向生成器通报参数3,末了返回 {done: true, value: undefined}


一个简朴的计数器

function* count(){
    var n = 1;
    while(true){
        yield n++;
    }
}

var it = count();
it.next(); // 1
it.next(); // 2
it.next(); // 3

用同步体式格局写异步代码

之前处置惩罚异步 ajax 要求效果,平常采纳通报回调函数的体式格局。一旦碰到多层回调嵌套,代码的可读性会下降,而且调试起来也不方便。有了生成器以后,我们就能够用同步的体式格局写异步的代码。这听上去异常的有意思。我们的代码将会是如许的

function foo(){
    var result = asyncFun(); // asyncFun 是异步函数,result 是异步返回的效果
    console.log(result);
}

固然,上面的代码并不能获得准确的效果,它只是一个想象。我们正盘算用生成器来完成,而且这是可行的。想一想生成器有哪些特性:

  1. 它能停息,向外部返回值
  2. 能继承实行剩下的代码,并接收外部传来的参数

这就足够了。有了生成器函数,如今我们重新来设想代码:

function* foo(){
    // 这里碰到了异步要领,必需停下来。
    // 守候异步要领实行终了,并返回效果,继承运转代码。固然,同步 ajax 不能算,它不是异步
    // 输出效果
}

静下来想一想有哪些症结字,与停息、继承有关。停下来…继承…停下来…继承…停下来…继承…Don’t…Stop…Don’t…Stop…Don’t…Stop……这两个词就是 yieldnext.

function *foo(){
    var result = yield asyncFun(next);
    console.log(result);
}

当代码碰到 yield 会停息,这个时刻 asyncFun 函数是不会停息的,会实行,等实行终了,再挪用生成器的 next 要领,并将返回效果作为参数传给 next。因为在生成器函数内部我们拿不到 next,必需借助于全局变量来通报 next

var next, gn;

function asyncFun(next){
    // 模仿异步要求
    setTimeout(function(){
        // 返回一个随机数
        next(Math.random())
    }, 1000)
}

function* foo(){
    var result = yield asyncFun(next);
    console.log(result);
}

gn = foo();
next = gn.next.bind(gn);
next(); // 打印随机数

如许写,运转看上去有些沉重。能够写一个包装函数运转含有异步代码的生成器函数。

function asyncFun(next){
  // 模仿异步要求
  setTimeout(function(){
    // 返回一个随机数
    next(Math.random())
  }, 1000)
}

function* foo(){
  var result = yield function(next){asyncFun(next)};
  console.log(result);
}



function wrapFun (gFn){
  var gn = foo(),
      next = gn.next.bind(gn);
  next().value(next);
}

wrapFun(foo);

演示地点

不过,自从出了 Promiseawait 以后,更多的是用这个组合,其运用也更简朴,局限也更广。

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