What can I yield?
浏览器支持情况: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内部封装了onFulfilled和onRejected函数,当yield右侧的promise resolve之后,则会调用onFullfield函数,onFullfield有一个关键的地方是:会调用gen.next(res)方法,用以给yield表达式赋值并执行下一次迭代。
co到底做了什么?我们先来看一段源码。
//这是一个thunk函数,只不过是用做倒计时
function sleep(msg) {
return function(done){
setTimeout(function (){
done("", msg)
}, 1000);
}
}
//Generator
function * G(msg){
return yield sleep(msg);
}
//Promise
function P(msg){
return new Promise(function (resolve, reject){
setTimeout(function (){
resolve(msg);
}, 1000)
});
}
//Thunk
function Thunk(msg){
return function (callback){
setTimeout(function (){
callback("", msg);
}, 1000)
}
}
//step 1
co(function *(){
console.log("before co");
//step 2
var generatorResult = yield G("Generator");
console.log("after result " + generatorResult);
//step 3
var promiseResult = yield P("Promise");
console.log("after result " + promiseResult);
var thunkResult = yield Thunk("Thunk");
console.log("after result " + thunkResult);
console.log("after co");
});
//console.log 结果
2016-05-26 11:38:57.578 before co
2016-05-26 11:38:58.584 index.js:37 after result Generator
2016-05-26 11:38:59.588 index.js:40 after result Promise
2016-05-26 11:39:00.590 index.js:43 after result Thunk
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
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
return null;
}
- step 2:调用next方法后会获得
G("Generator")的返回值,判断执行后是一个Generator,然后再继续step 1逻辑,这时再调用onFulfilled方法后next方法获得是一个Thunk函数,并且把Thunk通过方法thunkToPromise封装为Promise,注意这个thunkToPromise方法
//co.js
function thunkToPromise(fn) {
var ctx = this;
return new Promise(function (resolve, reject) {
fn.call(ctx, function (err, res) {
if (err) return reject(err);
if (arguments.length > 2) res = slice.call(arguments, 1);
resolve(res);
});
});
}
这个Thunk的参数是一个function,并且返回值第一个是err,第二个真实的值,这个是node回调规范,当回调执行后,就会触发resolve方法,在resolve里已经注册了onFulfilled方法,会触发Generator的next方法,把值通过Generator的next机制传递到generatorResult变量里。这样step2就完成了。
注意co里的next方法很有意思,注意第四行代码。
//co.js
function next(ret) {
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
+ 'but the following object was passed: "' + String(ret.value) + '"'));
}
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));
}
Object:遍历对象,把每一项推到数组里,用Promise.all方法封装
```javascript
//co.js
function objectToPromise(obj){
var results = new obj.constructor();
var keys = Object.keys(obj);
var promises = [];
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var promise = toPromise.call(this, obj[key]);
if (promise && isPromise(promise)) defer(promise, key);
else results[key] = obj[key];
}
//遍历对象,把每一项推到数组里,用Promise.all方法封装
return Promise.all(promises).then(function () {
return results;
});
function defer(promise, key) {
// predefine the key in the result
results[key] = undefined;
promises.push(promise.then(function (res) {
results[key] = res;
}));
}
}
What can I yield?的更多相关文章
- Python 生成器与迭代器 yield 案例分析
前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...
- node 异步回调解决方法之yield
先看如何使用 使用的npm包为genny,npm 安装genny,使用 node -harmony 文件(-harmony 为使用es6属性启动参数) 启动项目 var genny= require( ...
- yield生成器及字符串的格式化
一.生成器 def ran(): print('Hello world') yield 'F1' print('Hey there!') yield 'F2' print('goodbye') yie ...
- Python中的生成器与yield
对于python中的yield有些疑惑,然后在StackOverflow上看到了一篇回答,所以搬运过来了,英文好的直接看原文吧. 可迭代对象 当你创建一个列表的时候,你可以一个接一个地读取其中的项.一 ...
- Python yield函数理解
Python中的yield函数的作用就相当于一个挂起,是不被写入内存的,相当于一个挂起的状态,用的时候迭代,不用的时候就是一个挂起状态,挂起状态会以生成器的状态表现
- ecma6 yield
function * generator(k){ console.log('begin'); var x = yield k; console.log('x:',x); var y = yield x ...
- Python yield与实现
Python yield与实现 yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭 ...
- 可惜Java中没有yield return
项目中一个消息推送需求,推送的用户数几百万,用户清单很简单就是一个txt文件,是由hadoop计算出来的.格式大概如下: uid caller 123456 12345678901 789101 12 ...
- 使用yield进行异步流程控制
现状 目前我们对异步回调的解决方案有这么几种:回调,deferred/promise和事件触发.回调的方式自不必说,需要硬编码调用,而且有可能会出现复杂的嵌套关系,造成"回调黑洞" ...
- GetEnumerator();yield
GetEnumerator()方法的实质实现: 说明:只要一个集合点出GetEnumerator方法,就获得了迭代器属性,就可以用MoveNext和Current来实现foreach的效果,如上图. ...
随机推荐
- VMware Workstation 永久许可证密钥
VMware是功能最强大的虚拟机软件,用户可在虚拟机同时运行各种操作系统,进行开发.测试.演示和部署软件,虚拟机中复制服务器.台式机和平板环境,每个虚拟机可分配多个处理器核心.主内存和显存. VMwa ...
- Android 自己定义ImageView实现圆角/圆形 附加OnTouchListener具体凝视以及Button圆角
转载请注明出处:王亟亟的大牛之路 平时要用一些非方方正正的button之类的小伙伴们是怎样实现的?RadioButton? ImageButton? 还是其它? 今天亟亟上的是ImageView来实现 ...
- VTK学习之路——画画我的小苹果
数据集主要由描写叙述数据集几何形状的点集数据及构成数据集的单元构成,因此构建数据集的主要任务就是确定点集和构建单元,本演示样例程序构建了一个苹果的实体,然后绘制苹果.演示样例程序运行的过程例如以下: ...
- IOS中公布应用程序,进度条一直不走怎么处理
在IOS中公布应用程序非常是喜闻乐见. 近期1周.我更新了6次版本号.可是时不时的会卡住,进度条不走. 最后总结了几个原因. 1.在公布前你要确认自己的证书是否配置正确 2.DNS域名server有没 ...
- Django之邮件发送
settings.py #settings 添加如下配置进行邮件发送 #邮件服务器 EMAIL_HOST = "smtp.qq.com" #邮件发送的端口 EMAIL_PORT = ...
- leetCode 84.Largest Rectangle in Histogram (最大矩形直方图) 解题思路和方法
Given n non-negative integers representing the histogram's bar height where the width of each bar is ...
- Oracle学习第三篇—多行函数
0 order by asc/desc 默认升序 order by 列的名字|表达式|别名|序号 把空放在后边:order by desc nulls last 1分组函数--会自动滤空值 count ...
- Android OkHttp的Cookie自己主动化管理
Android中在使用OkHttp这个库的时候.有时候须要持久化Cookie,那么怎么实现呢.OkHttp的内部源代码过于复杂,不进行深究.这里仅仅看当中的HttpEngineer里面的部分源代码,在 ...
- Maven 编译
pom.xml 添加插件 <build> <plugins> <plugin> <groupId>org.apache.maven.plugins< ...
- 高性能流媒体服务器EasyDSS前端重构(三)- webpack + vue + AdminLTE 多页面引入 element-ui
接上篇 接上篇<高性能流媒体服务器EasyDSS前端重构(二) webpack + vue + AdminLTE 多页面提取共用文件, 优化编译时间> 本文围绕着实现EasyDSS高性能流 ...