# 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)