学习yield这块的时候发现别人的博客写的不太清楚 所以自己写了个试了下
Generator 函数
Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。
一个Generator函数与普通function的区别就是函数名前面多了一个星号 *
但是执行时有很大不同,与yield命令配合,可以实现暂停执行的功能
//公司代码风格没有分号,正在适应,不喜勿喷
let go = function*(x) {
console.log('x', x)
let a = yield x
console.log('xx', x)
console.log('a', a)
let b = yield x + 1
sum = a + b
yield a + b
return a + b
}
go(10)
//let g = go(10)
// (())
// ((1000).value)
// ((50).value)
// (().value)
上面代码打了很多log,用来发现generator函数和yield的执行方式,很原始但是很有效
如上,只执行了
go(10)
这一行代码,发现console是空的,所以说明 generator
函数被直接执行时是没有执行函数体内的代码的,否则应该执行 ('x', x)
,要让代码执行,需要通过 next()
函数
修改代码如下
let go = function*(x) {
console.log('x', x)
let a = yield x
console.log('xx', x)
console.log('a', a)
let b = yield x + 1
sum = a + b
yield a + b
return a + b
}
go(10)
let g = go(10)
console.log(())
// ((1000).value)
// ((50).value)
// (().value)
只是去掉了一行注释, 运行了 (().value)
这一行
结果为
x 10
Object {value: 10, done: false}
原来只有在调用了 next()
函数之后,函数才会开始执行,但是结果中没有看到打印的 xx
字样,所以应该是代码运行停在了 let a = yield x
这一行,所以 Object {value: 10, done: false}
就是yield的返回值,这个功能类似return
但是也有区别。
文档说,yield的返回是一个对象,包括 value
和 done
两部分,value自然是返回值,done是该generator函数是否执行完,这里看到false,就是表明该函数还有后续可以执行的部分。
再去掉一行注释,为了方便我把整个代码贴上
let go = function*(x) {
console.log('x', x)
let a = yield x
console.log('xx', x)
console.log('a', a)
let b = yield x + 1
sum = a + b
yield a + b
return a + b
}
go(10)
let g = go(10)
console.log(())
console.log((1000).value)
// ((50).value)
// (().value)
结果也贴上
x 10
Object {value: 10, done: false}
//以下是新出现的结果
xx 10
a 1000
11
首先看到了xx开头的log,表明代码是从刚才yield的地方开始执行的,然后注意,代码中有刚才第一个yield是这么写的
let a = yield x
console.log('xx', x)
console.log('a', a)
在yield之后是两个log,一个是xx上一步用来辨别代码执行到了哪里,另一个a的值,是刚才从yield获取的 let a = yield x
,从结果来看,a是1000,这和我第二次调用next()
时所用的参数值是一样的。
根据赋值语句的执行顺序,let a = b + c
会先计算 b + c 的值,然后在做赋值操作,同理
第一次调用next() 时,yield 把 x 的值 扔到了外面作为next()的返回值,赋值语句本身并没有来得及执行就暂停了,所以当第二次next() 函数调用时,函数是从赋值语句开始的,第二次的next()的参数1000,也作为原yield关键字的值传递给了a,所以才会看到结果中的 a 1000
如果没有这个1000,a是什么呢?
a undefined
所以,next()如果没有参数,当generator继续执行时,上次跳出所用的yield将是undefined
这次来看看generator的结束
let go = function*(x) {
console.log('x', x)
let a = yield x
console.log('xx', x)
console.log('a', a)
let b = yield x + 1
sum = a + b
yield sum
return sum
}
go(10)
let g = go(10)
console.log(g.next())
console.log(g.next().value)
//这里加了三个
console.log(g.next(50))
console.log(g.next(8))
console.log(g.next(8))
结果
x 10
Object {value: 10, done: false}
xx 10
a 1000
11
//本次增加的log
Object {value: 1050, done: false}
{value: 1050, done: true}
{value: undefined, done: true}
可以推测出,这次传入的50,是赋值给了b,然后sum = a + b 自然是1050,代码运行停止在了yield sum
,返回1050,
后一次调用next(),虽然传入了8,但是没有被接收,所以没有什么用,程序执行到了return
,
返回的结果自然还是1050,但是由于generator 结束了,next()方法的返回值中的done
也变成了true,表示没有下一个next()可以操作了。当然如果用了,也不会报错,只是如结果所示,因为已经找不到什么可以执行的代码了,所以只能是undefined
,同时done
的值还是true
仅以本文作为笔记方便自己以后忘记时理解