博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
yield next和yield* next的区别
阅读量:6669 次
发布时间:2019-06-25

本文共 3507 字,大约阅读时间需要 11 分钟。

  yield next和yield* next之间到底有什么区别?为什么需要yield* next?经常会有人提出这个问题。虽然我们在代码中会尽量避免使用yield* next以减少新用户的疑惑,但还是经常会有人问到这个问题。为了体现自由,我们在koa框架内部使用了yield* next,但是为了避免引起混乱我们并不提倡这样做。

  相关文档,可以查看这里的说明.

yield委托(delegating)做了什么?

  假设有下面两个generator函数:

function* outer() {  yield 'open'  yield inner()  yield 'close'}function* inner() {  yield 'hello!'}

  通过调用函数outer()能产出哪些值呢?

var gen = outer()gen.next() // -> 'open'gen.next() // -> a generatorgen.next() // -> 'close'

  但如果我们把其中的yield inner()改成yield* inner(),结果又会是什么呢?

var gen = outer()gen.next() // -> 'open'gen.next() // -> 'hello!'gen.next() // -> 'close'

  事实上,下面两个function本质上来说是等价的:

function* outer() {  yield 'open'  yield* inner()  yield 'close'}function* outer() {  yield 'open'  yield 'hello!'  yield 'close'}

  从这个意义上来说,委托的generator函数替代了yield*关键字的作用!

这与Co或Koa有什么关系呢?

  Generator函数已经很让人抓狂了,它并不能帮助的generator函数使用来控制流程。很多人都会被本地的generator函数和Co框架提供的功能搞晕。

  假设有以下generator函数:

function* outer() {  this.body = yield inner}function* inner() {  yield setImmediate  return 1}

  如果使用Co,它实际上等价于下面的代码:

function* outer() {  this.body = yield co(function inner() {    yield setImmediate    return 1  })}

  但是如果我们使用yield委托,完全可以去掉Co的调用:

function* outer() {  this.body = yield* inner()}

  那么最终执行的代码会变成下面这样:

function* outer() {  yield setImmediate  this.body = 1}

  每一个Co的调用都是一个闭包,因此它会或多或少地存在一些性能上的开销。不过你也不用太担心,这个开销不会很大,但是如果使用委托yield,我们就可以降低对第三方库的依赖而从代码级别避免这种开销。

有多快?

  这里有一个链接,是之前我们讨论过的有关该话题的内容:. 你不会看到有太多的性能差异(至少在我们看来),特别是因为实际项目中的代码会显著地降低这些基准。因此,我们并不提倡使用yield* next,不过在内部使用也并没有坏处。

  有趣的是,通过使用yield* next,Koa比Express要快!Koa没有使用dispatcher(调度程序),这与Express不同。Express使用了许多的调度程序,如connect, router等。

  使用委托yield,Koa事实上将:

co(function* () {  var start = Date.getTime()  this.set('X-Powered-By', 'koa')  if (this.path === '/204')    this.status = 204  if (!this.status) {    this.status = 404    this.body = 'Page Not Found'  }  this.set('X-Response-Time', Date.getTime() - start)}).call(new Context(req, res))

  拆解成:

app.use(function* responseTime(next) {  var start = Date.getTime()  yield* next  this.set('X-Response-Time', Date.getTime() - start)})app.use(function* poweredBy(next) {  this.set('X-Powered-By', 'koa')  yield* next})app.use(function* pageNotFound(next) {  yield* next  if (!this.status) {    this.status = 404    this.body = 'Page Not Found'  }})app.use(function* (next) {  if (this.path === '/204')    this.status = 204})

  一个理想的Web application看起来就和上面这段代码差不多。在上面使用Co的那段代码中,唯一的开销就是启动单个co实例和我们自己的Context构造函数,方便起见,我们将node的req和res对象封装进去了。

使用它进行类型检查

  如果将yield*应用到不是generator的函数上,你将会看到下面的错误:

TypeError: Object function noop(done) {  done();} has no method 'next'

  这是因为基本上任何具有next方法的东西都被认为是一个generator函数!就我个人而言,我很喜欢这个,因为默认我会假设我就是一个yield* gen()。我重写了很多我的代码来使用generator函数,如果我看到某些东西没有被写成generator函数,那么我会想,我可以将它们转换成generator函数而使代码更简化吗?

  当然,这也许并不适用于所有人,你也许能找到其它你想要进行类型检查的原因。

上下文

  Co会在相同的上下文中调用所有连续的可yield的代码。如果你想在yield function中改变调用的上下文,会有些麻烦。看下面的代码:

function Thing() {  this.name = 'thing'}Thing.prototype.print = function (done) {  var self = this  setImmediate(function () {    console.log(self.name)  })}// in koaapp.use(function* () {  var thing = new Thing()  this.body = yield thing.print})

  这里你会发现this.body是undefined,这是因为Co事实上做了下面的事情:

app.use(function* () {  var thing = new Thing()  this.body = yield function (done) {    thing.print.call(this, done)  }})

  而这里的this指向的是Koa的上下文,而不是thing。

  上下文在JavaScript中很重要,在使用yield*时,可以考虑使用下面两种方法之一:

yield* context.generatorFunction()yield context.function.bind(context)

  这样可以让你避开99%的generator函数的上下文问题,从而避免了使用yield context.method给你带来的困扰!

转载地址:http://wqoxo.baihongyu.com/

你可能感兴趣的文章
python获取软件安装列表2222
查看>>
gitlab的使用方法
查看>>
.Net之路(十三)数据库导出到EXCEL
查看>>
KMP算法 - 求最小覆盖子串
查看>>
excel VLOOKUP函数的用法
查看>>
JVM 类加载过程
查看>>
怎样查看修改sqlserver数据库的编码格式
查看>>
Ubuntu 14.10安装SecureCRT 7.3
查看>>
Windows XPE 安装
查看>>
Android学习之Spinner
查看>>
正则表达式
查看>>
sublime text格式化插件
查看>>
java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 解决方案
查看>>
FileSystem实例化过程
查看>>
使用Notepad++实现批量将ANSI转成为UTF-8编码
查看>>
Codeforces Round #280 (Div. 2) E. Vanya and Field 思维题
查看>>
SNF快速开发平台3.0之BS页面展示和九大优点-部分页面显示效果-Asp.net+MVC4.0+WebAPI+EasyUI+Knockout...
查看>>
LeetCode之Balanced Binary Tree 平衡二叉树
查看>>
傅里叶变换
查看>>
Android-BaseLine基础性开发框架
查看>>