目录
function* g(){
*:生成器函数的标识,在function关键字和函数名之间就可
yield “钱”
yield “多”
yield “多”
}
形式上,Generator函数是一个普通函数,但是有两个特征:
a.function关键字与函数名之间有一个星号*
b.函数体内部使用yiled表达式,定义不同的内部状态(yiled的意思是“产出”)
生成器函数调用,不会立即执行函数体,
而是返回一个Iterator遍历器对象,调用next()方法则继续往后执行,碰到yield关键字就暂停
const genObj = g()
console.log(genObj)
console.log(genObj.next())
console.log(genObj.next())
console.log(genObj.next())
console.log(genObj.next())
for(let item of g()){
console.log(item) }
输出:钱 多
只输出一个“多“的原因:(只限在Genterator函数中,在其他函数中正常遍历)
for item of循环碰到done为true的地方就结束了,只输出done为false的部分
function * g(a){
const b = 2*(yield(a-1))
const c = yield(b/4)
return (a-b+c)
}
const o = g(2)
console.log(o.next()) //输出:{ value:1,done:false }
console.log(o.next(6)) //输出:{ value:3,done:false }
(yield(a-1)) = 6 则b = 12
console.log(o.next(3)) //输出:{ value:-7,done:true }
yield(b/4) = 3 则c = 3 先前赋值:a = 2,b = 12 则return = -7
const b = g(3)
console.log(b.next()) //输出:{ value:4,done:false }
console.log(b.next(0)) //输出:{ value:0,done:false }
(yield(a-1)) = 0 则b = 0
console.log(b.next(1)) //输出:{ value:4,done:true }
yield(b/4) = 1 则c = 1 先前赋值:a = 3,b = 0 则return = 4
如果在Genderator函数内部,调用另一个Genderator函数。
需要在前面的Genderator的函数体内部,自己手动完成。
function * g1(){
yield "冰";
yield "墩";
yield "墩";
}
function * g2(){
yield "雪";
//手动遍历 g1()
for(let i of g1()){
console.log(i)
}
yield "容";
yield "融";
}
for(let v of g2()){
console.log(v)
}
输出:雪 冰 墩 墩 容 融
上面代码中,g1和g2都是Genderator函数,在g2里面调用g1,就需要手动遍历g1()。
如果有多个Genderator函数嵌套,写起来就非常麻烦。
es6提供了 yield*表达式作为解决办法。
用来在一个Genderator函数里面执行另一个Genderator函数。
function *g2(){
yiled "雪";
yiled* g1()
yield "容";
yield "融";
}
示例
function * f1(){
yiled "北京"
}
function * f2(){
yiled "hello"
yiled f1()
yiled "东奥"
}
const gen = f2()
console.log(gen.next().value) 输出:“hello”
console.log(gen.next().value) 输出:一个遍历器对象
console.log(gen.next().value) 输出:“东奥”
function * f3(){
yiled "hello"
yiled* f1()
yiled "东奥"
}
const gen = f3()
console.log(gen.next().value) 输出:“hello”
console.log(gen.next().value) 输出:“北京”
console.log(gen.next().value) 输出:“东奥”
生成器函数的应用:
React中Redux-Saga(dva)中间件,就是生成器函数的典型应用场景
需求:每隔1s按照顺序输出1,2,3,4,5
for(let i = 1;i<=5;i++){
setTimeout(()=>{
console.log(1)
},1000)
}
输出:1s后同时输出1,2,3,4,5
改造:每隔1s按照顺序输出1,2,3,4,5
const delay = n =>new Promise(resolve =>{
setTimeout(()=>{
resolve(n)
},1000)
})
function * g(){
for(let i = 1;i<=5;i++){
const x = yield delay(i)
console.log(x)
}
}
function co(g){
const o = g()
next()
function next(a){
const {value,done} = o.next(a)
if(done) return
value.then(data=>{
next(data)
})
}
}
co(g)