generator浅析

217 阅读2分钟

与 Iterator 接口的关系

首先,我们要知道一下类数组之所以可以转为数组的原因,是因为有iterator遍历器。而Generator 函数既是状态机,又是一个遍历器对象生成函数。

模拟一个iterator的实现过程如下:

原理:任意一个对象的Symbol.iterator方法,等于该对象的遍历器生成函数,调用该函数会返回该对象的一个遍历器对象。

function fn(){
    let obj = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function(){
            let that = this;
            let index = 0;
            return {
                next(){
                    return {value:that[index],done:index++===that.length}  
                }
            }
        }
    }
    let arr = [...obj];
    console.log(arr,Array.isArray(arr));
 }
 fn();

再看一下通过generator实现的iterator接口:

原理:由于 Generator 函数就是遍历器生成函数,因此可以把 Generator 赋值给对象的Symbol.iterator属性,从而使得该对象具有 Iterator 接口。


function fns(){
    // 给类数组 添加迭代方法  generator用法  koa1 基于generator  dva
    let obj = {0:1,1:2,2:3,length:3,[Symbol.iterator]:function*(){
            let that = this;
            let index = 0;
            while(index !== that.length){
                yield that[index++];
            }
        }};
    let arr = [...obj];
    console.log(Array.isArray(arr),arr);
}
fns();

generator作用

1.解决异步编程的问题
function * fns(){
    let a = yield 1;
    console.log(a); // ?
    let b = yield 2;
    console.log(b);
    return b;
}

let it = fns();
let { value} = it.next(); // 第一次next传递参数是无意义的
it.next('100'); // 在传递参数 就会把结果传递给上一次yield的返回值
it.next('200');
let fs = require('mz/fs');
function * readAge(){
    let content = yield fs.readFile('./name1.txt','utf8');
    let age = yield fs.readFile(content,'utf8');
    return age;
}
function co(it){ // express + koa 中间件原理
    return new Promise((resolve,reject)=>{
        // 如果是异步迭代
        function next(r){ // 默认只要没有迭代完成 就不能的调用next
            let {value,done} = it.next(r);
            if(!done){ // 没有完成 他才是一个promise
                value.then(r=>{
                    next(r);
                },reject)
            }else{
                resolve(r);
            };
        }
        next();
    });
}
co(readAge()).then(data=>{
    console.log(data);
}).catch(err=>{
    console.log(err);
});

aysnc,await语法糖


// es7 async + await  node 7.6 以上  generator + co语法糖
// let fs = require('mz/fs');
async function  readAge(){ // 全部 async + await + promise
    try{
        let content = await fs.readFile('./name1.txt','utf8');
        let age = await fs.readFile(content,'utf8');
        return age;
    }catch(e){
        console.log('error',e);
    }
}
// async 函数之行后 返回的是一个promise
readAge().then(data=>{
    console.log(data);
}).catch(err=>{
    console.log(err);
});