js中生成器函数是一个特殊的函数,具有上一篇中展示出来的“暂停”的执行模式。但它仍然是一个函数,这意味着它仍然有一些基本的特性没有改变。例如它仍然可以接收参数(即输入),也能够返回值(即输出)。
function *foo(x, y) {
return x*y;
}
var it = foo(6, 7);
var res = it.next();
console.log(res); // {value: 42, done: true}
console.log(res.value); // 42
向生成器函数*foo()
传入实参6和7分别作为参数x和y。*foo()
向调用代码返回值42。
生成器函数*foo()
和普通函数在调用上有区别。事实上生成器函数只是创建了一个迭代器对象,把它赋值给变量it,用于控制生成器*foo()
。然后调用it.next()
,指示生成器*foo()
从当前位置开始继续运行,停在下一个yield
处或直到生成器结束。
next()
调用的结果是一个对象,它有一个value属性,持有从*foo()
返回的值,换句话说,yield会导致生成器在执行过程中发送出一个值,这类似于中间的return。
除了能够接收参数并提供返回值外,生成器还提供更强大的内建消息输入输出能力,通过yield
和next()
实现:
function *foo(x) {
var y = x * (yield);
return y;
}
var it = foo(6);
//启动生成器 *foo()
var res1 = it.next();
console.log(res1); // {value: undefined, done: false}
var res2 = it.next(7);
console.log(res2); // {value: 42, done: true}
console.log(res2.value); // 42
首先生成器函数调用时传入实参6,调用过程就创建了一个迭代器对象并赋值给变量it,然后调用it.next()
启动生成器函数,返回的对象赋值给res1,打印res1可以看到value值为undefined,通过var res2 = it.next(7);
再度启动生成器函数并传入7作为被暂停的yield表达式的结果值,所以此时该赋值语句实际上就是var y = 6 * 7;
,现在return y
返回值42作为调用it.next(7)
的结果。
yield
和next()
这一对的组合,在生成器的执行过程中构成了一个双向消息传递系统。
从上例可以看出,通过一个迭代器控制生成生成器函数的时候,似乎是在控制生成器函数本身,但有一个细微之处很容易忽略:每次构建一个迭代器,实际上就隐式构建了生成器的一个实例,通过这个迭代器来控制的是这个生成器实例。
同一个生成器的多个实例可以同时运行,甚至可以彼此交互:
function *foo() {
var x = yield 2;
z++;
var y = yield( x * z);
console.log(x, y, z);
}
var z = 1;
var it1 = foo();
var it2 = foo();
var val1 = it1.next().value;
var val2 = it2.next().value;
console.log(val1); // 2 <= yield 2
console.log(val2); // 2 <= yield 2
val1 = it1.next( val2 * 10 ).value;
val2 = it2.next( val1 * 5 ).value;
console.log(val1); // 40 <= x:20, z:2
console.log(val2); // 600 <= x:200, z:3
it1.next(val2 / 2); // 20 300 3
it2.next(val1 / 4); // 200 10 3
梳理上例的执行流程:
*foo()
的两个实例同时启动,两个next()分别从yield 2
语句得到值2val2*10
也就是2*10
,发送到第一个生成器实例it1,因此x得到值20。z从1增加到2,然后20*2通过yield
发出,将val1设置为40val1*5
也就是40*5
,发送到第二个生成器实例it2,因此x得到值200。z从2增加到3,然后200*3通过yield
发出,将val1设置为600val2/2
也就是600/2
,发送到第一个生成器实例it1,因此y得到值300,然后打印出 x y z值分别是20 300 3val1/4
也就是40/4
,发送到第二个生成器实例it2,因此y得到值90,然后打印出 x y z值分别是200 10 3
喜欢本文请扫下方二维码,关注微信公众号: 前端小二,查看更多我写的文章哦,多谢支持。