Generator(生成器)

304 阅读2分钟

es6提供的生成器generator生成的是迭代器。(function * fn(){yield xxx})

    function sum(){
        let r = [...arguments].join('');
        console.log(r)
    }
    
    let obj = {0:1,1:2,2:3,length:3}
    console.log([...obj])

上述代码第一个是可以使用es6的扩展运算符...来展开的,而obj则不可以,因为默认的obj是不能被迭代的。那么如果想要可以迭代,需要自己实现下面的代码。

    // 自己实现迭代器需要注意以下几点
    /*
        1、需要增加一个[Symbol.iterator]属性
        2、返回一个对象包含next属性,属性值为一个函数
        3、next函数返回一个对象,对象包括value和done属性,当donefalse的时候表示未迭代完成,为true的时候表示迭代完成
    
    */
    let o = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function(){
        let currentIndex = 0;
        let that = this;
        return {
            next(){
                return {value[currentIndex++],done:currentIndex-1 === that.length}
            }
        }
    }}
    
    // 使用生成器产生迭代器
    let o = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function *(){
        let index = 0;
        while(index!==this.length){
            yield this[index];
            index++;
        }
    }

生成器函数执行完返回一个迭代器

    function * say(){
        yield 'node'
        yield 'react'
        yield 'vue'
    }
    
    let it = say();
    let flag = false;
    do{
        let {value,done} = it.next()
        flag = done
    }while(!flag)

yield的返回值(next第一次传值是无意义的,以后的每次传值都是n-1次yield的返回值,例如next第二次传递200的时候,a的值为200)

    function * say(){
        let a = yield 'hello'
        console.log(a)
        let b = yield 'world'
        console.log(b)
        let c = yield 'xxx'
        console.log(c)
    }
    let it = say();
    it.next(100);
    it.next(200);
    it.next(300);

co+generator实现后一项依赖前一项的异步请求

    let fs = require('fs');
    function read(){
        return new Promise(function(resolve,reject){
            fs.readFile(file,'utf8',function(err,data){
                if(err) reject(err)
                resolve(data)
            })
        })
    }
    
    function * r(){
        let r1 = yield read('./1.txt');
        let r2 = yield read(r1);
        let r3 = yield read(r2);
        return r3
    }
    
    function co(it){
        return new Promise(function(resolve,reject){
            //使用迭代器实现 异步操作按顺序执行。
            function next(data){
                let {value,done} = it.next(data);
                if(done){
                    resolve(value)
                }else{
                    value.then(function(data){
                        next(data)
                    },reject)
                }
            }
            
            next()
        })
    }
    co(r()).then(function(data){
        console.log(data)
    })

两个工具函数promisify和promisifyAll

    function promisify(fn){
        return function(...args){
            return new Promise(function(resolve,reject){
                fn(...args,function(err,data){
                    if(err) reject(err)
                    resolve(data)
                })
            })
        }
    }
    
    function promisifyAll(obj){
        for(let key in obj){
            let fn = obj[key];
            if(typeof fn === 'function'){
                obj[key] = promisify(fn)
            }
        }
    }