Generator 生成器
- Genarator 不是函数
- 执行
var h = generator()
后,内部代码不会立即执行,而是处于暂停状态 - 执行
h.next()
后会激活状态,开始执行内部语句,直到遇到yield
,会执行yield
后的表达式并返回结果,然后又进入暂停状态 - 遇到
return
预示执行结束,返回的done
值为true
,无法继续执行 - 继续执行
h.next()
,value
就会为undefined
- 每次执行
h.next()
都会打破暂停状态,直到遇到下一个yield
或return
h.next()
返回值永远是{value:...,done:....}
的形式
Iterator 遍历器
数组,类数组对象,Set,Map 原生具有[Symbol.iterator]
属性,可以使用for...of
取值
const arr = [1, 2, 3, 4]
const iterator = arr[Symbol.iterator]()
[Symbol.iterator]
可以生成一个 Iterator 对象
// next使用
console.log(iterator.next()) // { value: 1, done: false }
...
console.log(iterator.next()) // { value: 4, done: true }
console.log(iterator.next()) // { value: undefined, done: true }
// for...of使用
let i
for (i of iterator) {
console.log(i) // 1 2 3 4
}
Generator 返回的也是 Iterator 对象
function* generator() {
yield 100
yield (function () {
return 200
})()
return 300
}
const g = generator()
console.log(g.next()) { value: 100, done: false }
for( let i of g ) {
console.log(i)
}
Generator 具体应用
yield 具有传递数据的功能,通过 next,会将yield
后表达式的值传递至value
中
next 向 yield 传递值,则是传到上一个执行完的 yield 语句前的变量中
var a = yield 200
var b = yield 200
g.next()
g.next(300) //传 到了变量a中
使用 yield*语句可以嵌套 Genarator
function* g1() {
yield 1
yield* g2()
yield 4
}
function* g2() {
yield 2
yield 3
} //
1,2,3,4 顺序
Thunk 函数
任何函数,只要有回调函数,就可以写成 Thunk 函数的形式
Thunk 函数:对多参数的函数进行封装,返回一个只接受一个回调函数参数的函数.
var Thunk = function (fn) {
return function (...args) {
return function (callback) {
args.push(callback)
return fn.apply(this, args)
}
}
}
var readFileThunk = Thunk(fs.readfile)
readFileThunk(fileA)(callback)
使用 thunkify 库
const thunk = thunkify(fs.readFile)
const readFileThunk = thunk('data1.json', 'utf-8')
readFileThunk((err, data) => {
// 获取文件内容
})
Generator 与异步操作
const readFileThunk = thunkify(fs.readFile)
const generator = function* () {
const r1 = yield readFileThunk('data1.json') //此时value等于Thunk函数,需要一个回调函数
const r2 = yield readFileThunk('data2.json')
}
const g = generator()
g.next().value((err, data1) => {
g.next(data1).value((err, data2) => {
//给r1传值,并且执行next,传入回调函数
g.next(data2) //给r2传值,执行next
})
})
自驱动
function run(generator) {
const g = generator()
function next(data) {
var res = g.next(data)
if (res.done) {
return res.value
}
res.value.then(function (data) {
//需要yield返回一个promise对象
next(data)
})
}
next()
}
run(generator)
co 库
const co = require('co')
const readFileThunk = thunkify(fs.readFile)
const gen = function* () {
const r1 = yield readFileThunk('data1.json')
console.log(r1.toString())
const r2 = yield readFileThunk('data2.json')
console.log(r2.toString())
}
const c = co(gen) //返回一个promise对象
Generator
的本质
介绍Generator
中,多次提到 暂停 这个词 ———— “暂停”才是Generator
的本质 ———— 只有Generator
能让一段程序执行到指定的位置先暂停,然后再启动,再暂停,再启动。
而这个 暂停 就很容易让它和异步操作产生联系,因为我们在处理异步操作时,即需要一种“开始读取文件,然后暂停一下,等着文件读取完了,再干嘛干嘛…”这样的需求。因此将Generator
和异步操作联系在一起,并且产生一些比较简明的解决方案,这是顺其自然的事儿,大家要想明白这个道理。
不过,JS 还是 JS,单线程还是单线程,异步还是异步,callback
还是callback
。这一切都不会因为有一个Generator
而有任何变化。