浏览器支持情况:Enabled by default in desktop Chrome 39 

一句话回答这个问题是:Promise,Thunks。为什么没有Generators?因为Generators被转为了Promise。

Koa使用的是co库。所以在co中定义yield后的语句是什么,koa就默认支持,比如:Promise,Thunks,Generators,Arrays,Object,注意这里的Array和Object的每一项,每一个值都必须是Promise,Thunks,Generators的一种。同时在co里的generator里的yield后面也只能是Promise,Thunks,Generators,最后所有Promise,Thunks,Generators,Arrays,Object都封装成了Promise。

流程图如下:

co内部封装了onFulfilledonRejected函数,当yield右侧的promise resolve之后,则会调用onFullfield函数,onFullfield有一个关键的地方是:会调用gen.next(res)方法,用以给yield表达式赋值并执行下一次迭代。

co到底做了什么?我们先来看一段源码。

  1. //这是一个thunk函数,只不过是用做倒计时
  2. function sleep(msg) {
  3. return function(done){
  4. setTimeout(function (){
  5. done("", msg)
  6. }, 1000);
  7. }
  8. }
  9. //Generator
  10. function * G(msg){
  11. return yield sleep(msg);
  12. }
  13. //Promise
  14. function P(msg){
  15. return new Promise(function (resolve, reject){
  16. setTimeout(function (){
  17. resolve(msg);
  18. }, 1000)
  19. });
  20. }
  21. //Thunk
  22. function Thunk(msg){
  23. return function (callback){
  24. setTimeout(function (){
  25. callback("", msg);
  26. }, 1000)
  27. }
  28. }
  29. //step 1
  30. co(function *(){
  31. console.log("before co");
  32. //step 2
  33. var generatorResult = yield G("Generator");
  34. console.log("after result " + generatorResult);
  35. //step 3
  36. var promiseResult = yield P("Promise");
  37. console.log("after result " + promiseResult);
  38. var thunkResult = yield Thunk("Thunk");
  39. console.log("after result " + thunkResult);
  40. console.log("after co");
  41. });
  42. //console.log 结果
  43. 2016-05-26 11:38:57.578 before co
  44. 2016-05-26 11:38:58.584 index.js:37 after result Generator
  45. 2016-05-26 11:38:59.588 index.js:40 after result Promise
  46. 2016-05-26 11:39:00.590 index.js:43 after result Thunk
  47. 2016-05-26 11:39:00.591 index.js:45 after co

后面的逻辑:

  • step 1:co函数拿到参数Generator后封装成一个Promise,并且立即执行onFulfilled方法,在onFulfilled方法里会调用co的Generator的next方法,获取到后面的表达式结果,并且传递给next方法。next方法会把传递值都转为promise
  1. function onFulfilled(res) {
  2. var ret;
  3. try {
  4. ret = gen.next(res);
  5. } catch (e) {
  6. return reject(e);
  7. }
  8. next(ret);
  9. return null;
  10. }
  • step 2:调用next方法后会获得G("Generator")的返回值,判断执行后是一个Generator,然后再继续step 1逻辑,这时再调用onFulfilled方法后next方法获得是一个Thunk函数,并且把Thunk通过方法thunkToPromise封装为Promise,注意这个thunkToPromise方法
  1. //co.js
  2. function thunkToPromise(fn) {
  3. var ctx = this;
  4. return new Promise(function (resolve, reject) {
  5. fn.call(ctx, function (err, res) {
  6. if (err) return reject(err);
  7. if (arguments.length > 2) res = slice.call(arguments, 1);
  8. resolve(res);
  9. });
  10. });
  11. }

这个Thunk的参数是一个function,并且返回值第一个是err,第二个真实的值,这个是node回调规范,当回调执行后,就会触发resolve方法,在resolve里已经注册了onFulfilled方法,会触发Generator的next方法,把值通过Generator的next机制传递到generatorResult变量里。这样step2就完成了。

注意co里的next方法很有意思,注意第四行代码。

  1. //co.js
  2. function next(ret) {
  3. if (ret.done) return resolve(ret.value);
  4. var value = toPromise.call(ctx, ret.value);
  5. if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  6. return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
  7. + 'but the following object was passed: "' + String(ret.value) + '"'));
  8. }
  • step 3,这一步就是step2的简化版,当promise的resolve方法执行后,会触发onFulfilled方法,继续把值通过Generator的next机制传递到promiseResult变量里

  • 同理 step 4

知道这些就可以很好的使用co方法,来做到同步书写代码了。我们可以在yield后面传递Array,Object看完源码就一目了然。

Array:是把数组每一项转化为Promise,然后用all方法

​```javascript

//co.js

function arrayToPromise(obj) {

return Promise.all(obj.map(toPromise, this));

}


  1. Object:遍历对象,把每一项推到数组里,用Promise.all方法封装
  2. ```javascript
  3. //co.js
  4. function objectToPromise(obj){
  5. var results = new obj.constructor();
  6. var keys = Object.keys(obj);
  7. var promises = [];
  8. for (var i = 0; i < keys.length; i++) {
  9. var key = keys[i];
  10. var promise = toPromise.call(this, obj[key]);
  11. if (promise && isPromise(promise)) defer(promise, key);
  12. else results[key] = obj[key];
  13. }
  14. //遍历对象,把每一项推到数组里,用Promise.all方法封装
  15. return Promise.all(promises).then(function () {
  16. return results;
  17. });
  18. function defer(promise, key) {
  19. // predefine the key in the result
  20. results[key] = undefined;
  21. promises.push(promise.then(function (res) {
  22. results[key] = res;
  23. }));
  24. }
  25. }

What can I yield?的更多相关文章

  1. Python 生成器与迭代器 yield 案例分析

    前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...

  2. node 异步回调解决方法之yield

    先看如何使用 使用的npm包为genny,npm 安装genny,使用 node -harmony 文件(-harmony 为使用es6属性启动参数) 启动项目 var genny= require( ...

  3. yield生成器及字符串的格式化

    一.生成器 def ran(): print('Hello world') yield 'F1' print('Hey there!') yield 'F2' print('goodbye') yie ...

  4. Python中的生成器与yield

    对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...

  5. Python yield函数理解

    Python中的yield函数的作用就相当于一个挂起,是不被写入内存的,相当于一个挂起的状态,用的时候迭代,不用的时候就是一个挂起状态,挂起状态会以生成器的状态表现

  6. ecma6 yield

    function * generator(k){ console.log('begin'); var x = yield k; console.log('x:',x); var y = yield x ...

  7. Python yield与实现

    Python yield与实现  yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...

  8. 可惜Java中没有yield return

    项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...

  9. 使用yield进行异步流程控制

    现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...

  10. GetEnumerator();yield

    GetEnumerator()方法的实质实现: 说明:只要一个集合点出GetEnumerator方法,就获得了迭代器属性,就可以用MoveNext和Current来实现foreach的效果,如上图. ...

随机推荐

  1. HTML字体对应word字体

    42磅对应初号. 36磅对应小初. 26磅对应一号. 24磅对应小一号. 22磅对应二号. 18磅对应小二号. 16磅对应三号. 15磅对应小三号. 14磅对应四号. 12磅对应小四号. 10.5磅对 ...

  2. VueJS表单控件操作

    概念说明 v-model指令:在表单控件元素上创建双向数据绑定.v-model 会根据控件类型自动选取正确的方法来更新元素. 输入框 实例中演示了 input 和 textarea 元素中使用 v-m ...

  3. js运算【按位非】~

    这个运算符有点意思:按位非[~] 先来几个例子: ~undefined: -1 ~false: -1 ~true: -2 ~10:-11 找出规律了吧~~ 再说一下运用场景: 之前判断字符串是否存在是 ...

  4. HDFS源码分析心跳汇报之周期性心跳

    HDFS源码分析心跳汇报之周期性心跳,近期推出!

  5. mongodb的IO测试工具 mongoperf

    之前没发现mongoperf这个工具,测试IO的状态用的是iostat来进行观察. mongoperf < myjsonconfigfile  echo "{nThreads:2,fi ...

  6. 07 redi sorder set结构及命令详解

    zadd key score1 value1 score2 value2 .. 添加元素 redis 127.0.0.1:6379> zadd stu 18 lily 19 hmm 20 lil ...

  7. android 底部菜单栏实现(转)

    1.Android学习之BottomNavigationBar实现Android特色底部导航栏 2.Android底部导航栏的四种实现 3.Android BottomNavigationBar底部导 ...

  8. sigar 监控服务器硬件信息

    转载 http://www.cnblogs.com/jifeng/archive/2012/05/16/2503519.html 通过使用第三方开源jar包sigar.jar我们可以获得本地的信息 1 ...

  9. php类中const

    常量 const 在类里面定义常量用 const 关键字,而不是通常的 define() 函数. 语法: const constant = "value"; 例子: <?ph ...

  10. H2 应用实例1

    说明:本例子开发工具为NetBeans,jdk 1.7 进行测试说明 H2安装说明如下 1. H2数据库必要文件下载地址为: http://www.h2database.com     (1) 下载截 ...