ES6-Generator

Generator

关键词:状态机,遍历器,同步方式写异步方法git

基本概念

  • 形式上,Generator函数是一个普通函数,可是有两个特征。
    • function关键字与函数名之间有一个星号。
    • 二是,函数体内部使用yield语句,定义不一样的内部状态。
function* helloWorldGenerator() {
    yield 'hello';
    yield 'world';
    return 'ending';
}
var hw = helloWorldGenerator();
var h = helloWorldGenerator();
  • 调用Generator函数,返回一个遍历器对象,表明Generator函数的内部指针。
// 接上面的demo

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

yield语句

  • yield语句不能用在普通函数中,不然会报错
(function (){
    yield 1;
})()
  • yield语句若是用在一个表达式之中,必须放在圆括号里面
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError

console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
  • yield语句用做函数参数或赋值表达式的右边,能够不加括号
foo(yield 'a', yield 'b'); // OK
let input = yield; // OK

return()

  • 若是主动调用return()方法,Generator函数将被终结
function* gen(){
    yield 1;
    yield 2;
    yield 3;
}
var g = gen();
g.next() // {value: 1, done: false}
g.return('foo') // {value: 'foo', done: true}
g.next() // {value: undefined, done: true}
  • 可是,若是Generator函数内部有try...finally代码块,那么return方法会推迟到finally代码块执行完再执行。
function* gen(){
    try{
        yield 1;
    }finally{
        yield 2;
    }
    yield 3;
}
var g = gen();
g.next() // {value: 1, done: false}
g.return(10) // {value: 2, done: false}
g.next() // {value: 10, done: true}

yield*

  • 在一个Generater函数内部直接调用另一个Generater函数无效
function* outer(){
    yield 1;
    yield inner();
    return 3;
}
function* inner(){
    yield 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: inner, done: false}
o.next(); // {value: 3, done: true}
  • 上面的状况能够使用yield*解决
function* outer(){
    yield 1;
    yield* inner(); // 调用方法与上面不一样
    return 3;
}
function* inner(){
    yield 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: 2, done: false} // 返回结果与上面不一样
o.next(); // {value: 3, done: true}
  • 任何数据结构只要有Iterator接口,就能够被yield*遍历。
function* demo(){
    yield* [1, 2, 3];
}
var d = demo();
d.next(); // {value: 1, done: false}
d.next(); // {value: 2, done: false}
d.next(); // {value: 3, done: false}
d.next(); // {value: undefined, done: true}
  • 若是被代理的Generator函数有return语句,那么就能够向代理它的Generator函数返回数据。
function* outer(){
    yield 1;
    var i = yield* inner();
    yield 2 + i;
}
function* inner(){
    return 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: 4, done: false}

做为对象属性的Generator函数

  • 若是一个对象的属性是Generator函数,能够简写成下面的形式。
let obj = {
    * gen(){
        yield 1;
    }
};
var g = obj.gen();
g.next(); // {value: 1, done: false}

Generator函数的this

应用

  • 异步操做的同步化表达,逻辑更清晰
function* render(){
    showLoading();
    var res = yield getData();
    hideLoading();
    console.log(res); // 打印ajax的结果
}
function getData(){
    $.ajax().done(function(res){
        r.next(res);
    });
}
var r = render();
r.next();
  • 控制流管理,摆脱回调函数多层嵌套
// callback方式
function step(){
    step1(function(res1){
        step2(res1, function(res2){
            step3(res2, function(res3){
                console.log(res3);
            })
        })
    })        
}
// promise方式
function step(){
    step1()
    .then(step2)
    .then(step3)
    .then(function({
        // do something
    }))        
}
// Generator方式
function step(){
    var res1 = yield step1();
    var res2 = yield step2(res1);
    var res3 = yield step3(res2);
}
  • 多任务并行。若是yield语句后面的参数,是一个具备遍历器接口的对象,yield会遍历这个对象,再往下执行。这意味着,多个任务按顺序一个接一个执行时,yield语句能够按顺序排列。多个任务须要并列执行时(好比只有A任务和B任务都执行完,才能执行C任务),能够采用数组的写法。
function execTaskA(){
    return new Promise(function(resolve, reject){
        if(true){
            resolve('a')
        }
    })
}
function execTaskB(){
    return new Promise(function(resolve, reject){
        if(true){
            resolve('b')
        }
    })
}
function* execTasks(){
    var [resA, resB] = yield [execTaskA(), execTaskB()];
    // let resB = yield* execTaskB();
    console.log(resA, resB);
}
var t = execTasks();
t.next();
  • 关于Generator函数的自动执行,能够关注github上的co组件