# generator及co库原理

# generator的基础用法

我们先来看下generator的基本用法




 







function* read() {
    console.log(1)
    yield 1
    console(2)
    yield 2
    return 3
}
let it = read()
it.next() // 1
it.next() // 2

generator叫生成器,用来生成迭代器(it),我们需要通过调用it.next让迭代器往前走一步,遇到yield就会停止

我们在来看一个例子




 








function* read() {
    let a = yield 1
    console.log(a) //hello
    let b = yield 2
    console.log(b) //chenying
    return b
}
let it = read()
it.next()
it.next('hello')
it.next('chenying') 

我们可以发现,第一次调用next传进去的参数是无效的,从第二个next开始传入的参数会作为上一个yield的返回值,如上述代码中第二个next传入的参数hello会作为上一个yeild的返回值,也就是赋值给a

另外it.next()会返回一个对象{ value: xxx, done: false/true }, value是值,done表示是否运行到最后

# generator的应用

我们可以通过generator + promise实现异步调用,同样的需求,我们需要读取name.txt的内容,然后根据这个内容读取对应文件夹的值

我们可以这样来实现




 
















let fs = require('fs').promises
function* read() {
    try {
        let content = yield fs.readFile('./name.txt', 'utf8')
        let age = yield fs.readFile(content, 'utf8')
        return age
    } catch(e) {
        console.log(e)
    }
}
let it = read()
let { value } = it.next()
value.then((data) => { //age.txt
    let { value } =  it.next(data)
    value.then((data) => {
        let { value } = it.next(data)
        console.log(value)
    })
})

通过手动的next()就可以实现这类型的需求,但是我们可以发现代码中有很多重复的部分,这个我们可以用co库来简化代码

# co库

我们直接使用CO库来简化下代码




 










let fs = require('fs').promises
function* read() {
    try {
        let content = yield fs.readFile('./name.txt', 'utf8')
        let age = yield fs.readFile(content, 'utf8')
        return age
    } catch(e) {
        console.log(e)
    }
}
co(read()).then(data => {
    console.log(data)
})

我们可以发现使用co库之后代码变得非常的清晰

那我们最后来实现一个这个co库吧




 












function co (it) {
    return new Promise((resolve, reject) => {
        function next (data) {
            let { value, done } = it.next(data)
            if (!done) {
                Promise.resolve(value).then((data) => {
                    next(data)
                }, reject)
            } else {
                resolve(value)
            }
        }   
        next()
    })
}

关键核心点在于next函数,这个思路在很多框架中也有体现(koa,express)