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

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

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 generator
gen.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函数已经很让人抓狂了,它并不能帮助Koa的generator函数使用Co来控制流程。很多人都会被本地的generator函数和Co框架提供的功能搞晕。

  假设有以下generator函数:

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

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

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

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

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

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

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

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

有多快?

  这里有一个链接,是之前我们讨论过的有关该话题的内容:https://github.com/koajs/compose/issues/2. 你不会看到有太多的性能差异(至少在我们看来),特别是因为实际项目中的代码会显著地降低这些基准。因此,我们并不提倡使用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 = 204if (!this.status) {this.status = 404this.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* nextthis.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* nextif (!this.status) {this.status = 404this.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 = thissetImmediate(function () {console.log(self.name)})
}// in koa
app.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给你带来的困扰!

本文转自Jaxu博客园博客,原文链接:http://www.cnblogs.com/jaxu/p/6344366.html,如需转载请自行联系原作者

yield next和yield* next的区别相关推荐

  1. python yield from_python中yield的用法以及和yield from的区别

    看了大佬的博客很快就懂了. 由于最近接触了酷q机器人,搭建好了环境,配合NoneBot可以通过python代码自己写机器人功能. NoneBot是基于asyncio的,所以先通过yield来学习一点p ...

  2. 线程让步(yield)和线程睡眠(sleep)区别

    线程睡眠(sleep) 让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现.当前线程调用sleep()方法进入阻塞状态后,在其睡眠时间内,该线 ...

  3. php yield 导出文件,PHP yield 读取大文件

    今天来优化下读取大文件,在 PHP 读取大文件的时候,经常会出现内存不足的情况,如果文件过大的话,没法一次读取完,今天采用 yield 来实现大文件的读取.yield生成器是php5.5之后出现的,y ...

  4. python yield from yield_python yield和yield from用法总结详解 python yield和yield from用法总结...

    #!/usr/bin/env python # -*- coding: utf-8 -*-from inspect import isgeneratorfunction def fab(max): n ...

  5. python yield from_简述 yield 和 yield from

    yield 函数可以看成是一堆指令的集合.在函数中加入yield可以把一个函数变成一个generator,虽然调用的方式不一样了,但是其实现的功能和原来的函数基本是一样的. 而yield在这其中的作用 ...

  6. java thread yield()_Java Thread yield()方法

    Java Thread yield()方法 java.lang.Thread.yield() 方法使当前执行的线程对象来暂停并允许其他线程执行. 1 语法 public static void yie ...

  7. java线程中yield()和join()的区别

    多线程在面试中是非常受欢饮的题目,我个人认为我们很少有机会能够真正的用到复杂的多线程(我在7年前使用过一次),熟悉这些概念能够增加你的信心,先前,我已经讨论了一个相似的问题,wait()和sleep( ...

  8. yield和return的区别-- 超详细

    首先比较下return 与 yield的区别: return:在程序函数中返回某个值,返回之后函数不在继续执行,彻底结束. yield: 带有yield的函数是一个迭代器,函数返回某个值时,会停留在某 ...

  9. Python中yield和yield from的用法

    yield 后面接的是 future 对象 调用方 委托生成器 yield from 直接给出循环后的结果 yield from 委托者和子生成器直接通信 yield from 直接处理stopIte ...

最新文章

  1. 多路三线RTD电阻温度采集电路设计方案
  2. 报名 | 清华大学海外学者短期讲学:创新创业发展课程
  3. 腾讯130公顷的深圳新总部了解一下,大小相当于曼哈顿城
  4. JavaScript复制内容到剪贴板
  5. SQL点滴26—常见T-SQL面试解析
  6. git相关常用基本用法命令及分支操作指南命令
  7. 浅谈一下session问题
  8. 颠覆大数据分析之结论
  9. 摄影测量学之共线方程的应用
  10. 在windows生产环境搭建sphinx的注意事项
  11. poj2965--枚举专题 (算法巧妙)
  12. 学计算机的怎样分析TCGA数据库,TCGA一些数据库
  13. 行业下行,丧失亮点的OPPO慢人一步
  14. 雨后小故事动态邪恶_当您遇到“邪恶”的问题时,使故事变小
  15. QT 析构的报错Cannot send events to objects owned by a different thread.
  16. 面试必看:java面试考点精讲视频教程
  17. (—)容器——初识容器
  18. [小说]魔王冢(52)赵四爷
  19. 电源模块测试系统NSAT-8000
  20. 二维码报修系统的技术实现

热门文章

  1. 采用加密技术进行数据保护的5大优势
  2. 四大科技巨头跟随者众 智能家居市场容量可观
  3. Storm【技术文档】-Worker Executor Task的关系
  4. Socket.IO聊天室~简单实用
  5. 公司用云桌面还是台式计算机好,相比于性能更强的台式机为什么很多企业更喜欢用云桌面...
  6. matlab 柱面投影,matlab练习程序(圆柱投影)
  7. java表达式语法格式为_2009(选修)JavaWeb模拟试卷(2011-2012)
  8. 多路平衡查找树(B Tree)(分裂、合并)
  9. 策略模式Strategy Pattern应用场景
  10. 用户注册 - 判断用户名存在