前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《你不知道的JavaScript》:利用生成器实现消息传递

《你不知道的JavaScript》:利用生成器实现消息传递

作者头像
前端_AWhile
发布2019-08-29 13:11:33
5120
发布2019-08-29 13:11:33
举报
文章被收录于专栏:前端一会前端一会前端一会

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。

除了能够接收参数并提供返回值外,生成器还提供更强大的内建消息输入输出能力,通过yieldnext()实现:

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)的结果。

yieldnext()这一对的组合,在生成器的执行过程中构成了一个双向消息传递系统。

从上例可以看出,通过一个迭代器控制生成生成器函数的时候,似乎是在控制生成器函数本身,但有一个细微之处很容易忽略:每次构建一个迭代器,实际上就隐式构建了生成器的一个实例,通过这个迭代器来控制的是这个生成器实例。

同一个生成器的多个实例可以同时运行,甚至可以彼此交互:

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语句得到值2
  • val2*10也就是2*10,发送到第一个生成器实例it1,因此x得到值20。z从1增加到2,然后20*2通过yield发出,将val1设置为40
  • val1*5也就是40*5,发送到第二个生成器实例it2,因此x得到值200。z从2增加到3,然后200*3通过yield发出,将val1设置为600
  • val2/2也就是600/2,发送到第一个生成器实例it1,因此y得到值300,然后打印出 x y z值分别是20 300 3
  • val1/4也就是40/4,发送到第二个生成器实例it2,因此y得到值90,然后打印出 x y z值分别是200 10 3

-------------------------------- 热门文章 --------------------------------

设计模式>>>

javascript设计模式一: 单例模式

javascript设计模式二:策略模式

javascript设计模式三:代理模式

javascript设计模式四:迭代器模式

javascript设计模式五:原型模式

javascript设计模式六:发布-订阅模式(观察者模式)

javascript设计模式七:模板方法模式

javascript设计模式八:职责链模式

javascript设计模式九:中介者模式

javascript设计模式十:装饰者模式

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端小二 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档