zoukankan      html  css  js  c++  java
  • ES6-Generator

    Generator

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

    基本概念

    • 形式上,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组件
  • 相关阅读:
    COJ 1691:前缀和
    COJ 1692:模拟
    POJ 3415:后缀数组+单调栈优化
    python拓展知识
    git总结
    好的文章及博客收集
    python爬虫总结
    ajax与java后台交互
    Java多线程与并发库
    Django框架创建
  • 原文地址:https://www.cnblogs.com/ddfe/p/5609700.html
Copyright © 2011-2022 走看看