Generator

搬运自

http://es6.ruanyifeng.com/#docs/generator

如果没有babel等环境也可以在线体验

可以在http://www.es6fiddle.net/ OR https://babeljs.io/repl/ 在线编译ES6

Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。

带有星星的函数就是Generator

function* gen(x){....}

generator的关键字是yield和next yield关键字只能在带有星星的函数中使用

yield x+2; //yield的意思是产出 这里表示生产 x+2 这个值

而调用g.next() 则会一直执行到yield函数之前(也包括yield语句)或者说函数执行将会在yield 这句话这里卡住, 直到有个next()调用

来个最简单的例子


function* gen(){
yield 1;
yield 2;
}
var g0 = gen();
console.log(g0.next()); //{"value":1,"done":false} 返回的是一个对象 包括yield后面的结果 以及这个函数是否执行完毕
console.log(g0.next());
console.log(g0.next()); //执行结果
// {"value":1,"done":false}
// {"value":2,"done":false}
// {"done":true}

再来个复杂一点的, 深刻理解一下yield的执行过程

var y = 'heheh';

function* gen(x) {
console.log('start');
//因为第一句就是yield 所以函数到这里若没有调用 g.next()是没有执行的
//第一次调用 g.next() 则执完到第一个yield 之前的语句 以及计算需要yield的值
//也就是第一次调用 g.next() 执行了 第一句log('start) 和 yield x+2
y = yield x + 2;
//yield的意思是产出 这里表示生产 x+2 这个值
//看起来好像把 yield产出的值赋值给了y 实际上不是
//y的值是在下一次(也就是第二次调用的时候由 g.next() 传入的) console.log('2nd');
yield 2333;
//第二次调用 g.next() 执行到第二个yield语句这里
// console.log('3rd');
// return y;
} var g = gen(1);//此时并没有执行
console.log(g.next());
console.log('y is '+ y); //y仍是最初始的值
//输出
//start
// { value: 3, done: false }
//g.next().value 的结果是 yield后的值
console.log(g.next('haYYY')); // {"value":2333,"done":false}
console.log('y is '+ y); // y is haYYY //第三次调用 整个函数执行完毕
console.log(g.next());
//输出的结果包括
//3rd
//{"value":"haYYY","done":true} //第三次调用next() 其value就是*函数的返回值(因为已经木有yield语句了)
console.log('g is ',g); //{}

g = gen(1) 实际上这个函数没有执行

直到g.next()的时候才真正执行

我传入的x是2 所以这里yield x+2 实际上是 yield 3;

然后暂停了

第一个next 开始执行 语句一行一行的执行直到遇到一个yield停止

所以第一个得到yield 的结果 { value: 3, done: false }

那么y呢 y的值是 3 吗?

不是的 y的值是下一个next传入的值

刚才说到了第一个next就执行到 yield 3 这里

后来又 g.next('y') 这里传入了一个参数 'y'

这个字符串就是 yield x+1 这个表达式的返回值

第n个 next的参数 就是 第 n-1 个 yield的返回值

所以如果你在第一个next() 就传值的话 是没有意义的

PS 一个generator对象有n句 yield 总需要n+1句next() 才能走完整个流程

如何用Generator来实现异步呢

实际上就是把异步的函数放在 yield 关键字之后

yield后面可以接的对象有 function, promise, generator, array, object

另外需要借助co的支持

搬运https://cnodejs.org/topic/542953d42ca9451e1bf3c251

那么就可以像同步操作那样的写法来写异步函数

co(...) 使用时应向co传入一个generator对象

var co = require('co');
co(function* (){
var now = Date.now();
yield delay800;
console.log(Date.now() - now);
}); function delay800(cb) {
setTimeout(cb, 800);
}

这个例子的感受可能不明显 有了co和generator, 数据查询甚至可以变成这样

co(function *(){
var rs = yield db.query('select url from xxx');
rs.forEach(rs){
var content = yield getUrl(rs.url);
...
}
})();

co的原理

co的作用是可以使异步的函数放在 yield关键字之后 然后整个异步流程的代码写法可以像同步函数一样

并不是实现了一个generator

观察使用co的代码 co接受一个参数 该参数是一个generator函数

co(generator){ ... }

再看一般generator的调用 在一个generator函数执行后返回一个对象g 通过g.next()不断调用下一个函数

所以co要做的事情 就是接受generator 并且通过每一次next()的返回值判断是否执行完毕来看是否需要继续调用 g.next()

下面是co最简单的实现

参考 https://cnodejs.org/topic/53474cd19e21582e740117df

co(function* (){
var now = Date.now();
yield delay800; //yield后面应该接一个函数对象
yield delay500;
console.log(Date.now() - now);
}); function delay800(callRecurence) {
setTimeout(callRecurence, 800);
}
function delay500(callRecurence){
setTimeout(function(){
//some async ...
callRecurence();
},500)
}; function co(generator) {
var gen = generator();
function next(err, result) {
if(err){
return fn(err);
}
var step = gen.next(result); //{value: fn , done: false}
if (!step.done) {//没有执行完毕 继续next //执行异步函数 step.value 就是yield后的异步函数
//next 就是当前next(err,result)函数 通过递归的方式不断调用next达到多次调用 gen.next()
step.value(next);
} else {
// console.log('done!');
}
}
next();
}

Async

http://www.ruanyifeng.com/blog/2015/05/async.html

Async可以让你像使用同步函数一样来使用异步

await 后面是异步函数 该函数应当返回一个Promise

await只能存在于有async修饰的函数中


async function getAsyncRs(name) {
var symbol = await asyncFun1(name);
console.log(symbol);
var stockPrice = await asyncFun2(symbol);
return stockPrice;
} getAsyncRs('goog').then(function(result) {
console.log(result);
}); function asyncFun1(name) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve('async1' + name);
}, 500);
});
}
function asyncFun2(name) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve('async222' + name);
}, 1000);
});
}

Generator & Co的更多相关文章

  1. EasyMesh - A Two-Dimensional Quality Mesh Generator

    EasyMesh - A Two-Dimensional Quality Mesh Generator eryar@163.com Abstract. EasyMesh is developed by ...

  2. 轻量级“集合”迭代器-Generator

    Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Generator的改进之前,我们先通过一个简单却显而易见的例子来了解下G ...

  3. .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator

    去年,我在一篇文章用原始方法解析复杂字符串,json一定要用JsonMapper么?中介绍了简单的JSON解析的问题,那种方法在当时的环境是非常方便的,因为不需要生成实体类,结构很容易解析.但随着业务 ...

  4. 深入解析js异步编程利器Generator

    我们在编写Nodejs程序时,经常会用到回调函数,在一个操作执行完成之后对返回的数据进行处理,我简单的理解它为异步编程. 如果操作很多,那么回调的嵌套就会必不可少,那么如果操作非常多,那么回调的嵌套就 ...

  5. mybatis Generator生成代码及使用方式

    本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5889312.html 为什么要有mybatis mybatis 是一个 Java 的 ORM 框架,OR ...

  6. ABP配套代码生成器(ABP Code Generator)帮助文档,实现快速开发

    ABP代码生成器介绍 针对abp这个框架做了一个代码生成器,功能强大.分为两大功能点,一个是数据层,一个是视图层. 数据服务层:通过它,可以实现表设计.领域层初始化.多语言.automapper自动注 ...

  7. ES6笔记(5)-- Generator生成器函数

    系列文章 -- ES6笔记系列 接触过Ajax请求的会遇到过异步调用的问题,为了保证调用顺序的正确性,一般我们会在回调函数中调用,也有用到一些新的解决方案如Promise相关的技术. 在异步编程中,还 ...

  8. OData Client Code Generator

    转发. [Tutorial & Sample] How to use OData Client Code Generator to generate client-side proxy cla ...

  9. python generator next send

    *******oi********oi********oi 上面  *  符号 代表 一系列的代码, oi 代表 一个 [yield]关键字引出的 [数据交换,称之为 oi ] 在一个有[yield] ...

  10. 使用MyBatis Generator自动创建代码(dao,mapping,poji)

    连接的数据库为SQL server2008,所以需要的文件为sqljdbc4.jar 使用的lib库有: 在lib库目录下新建一个src文件夹用来存放生成的文件,然后新建generatorConfig ...

随机推荐

  1. FMDatabase 数据库的使用

    创建,插入,更新和删除:使用executeUpdate方法,而查询则用executeQuery 1.实例化FMDatabase //paths: ios下Document路径,Document为ios ...

  2. .NET之反射(1)

    .NET之反射 第一版 内容摘要 前言 反射 查看元数据 加载程序集 晚期绑定 方法调用 反射.晚期绑定和自定义特性的使用背景 参考资料 前言 关于反射的内容,向来是隐藏在C#高级编程类别中的大部头书 ...

  3. [Oracle]日期和毫秒转换(Date->int)

    --日期转换毫秒  SELECT TO_NUMBER(TO_DATE('2005-03-29 12:30:45', 'YYYY-MM-DD HH24:MI:SS') -  TO_DATE('1970- ...

  4. mysql性能优化学习笔记(5)数据库结构优化

    一.选择合适的数据类型    1.使用可存下数据的最小的数据类型    2.使用简单地数据类型,Int<varchar    3.尽可能使用not null定义字段    4.尽量少用text, ...

  5. struts2之动态方法调用(转)

    转自:http://blog.csdn.net/longwentao/article/details/6940289 当我们访问一个Action时,默认是访问execute()方法,但当在一个Acti ...

  6. opencv如何用模板匹配寻找目标

    首先使用: MatchTemplate 比较模板和重叠的图像区域 void cvMatchTemplate( const CvArr* image, const CvArr* templ, CvArr ...

  7. Oracle字符编码

    .检查服务器编码: 执行SQL语法: Java代码 select * from v$nls_parameters; 或 Java代码 select * from nls_database_parame ...

  8. QTcpSocket 及 TCP粘包分析

    ----我的生活,我的点点滴滴!! 这两天用Qt简单的实现一个tcp多线程client,在此记录下知识. 一.长连接与短连接 1.长连接 Client方与Server方先建立通讯连接,连接建立后不断开 ...

  9. KO.js学习笔记(一)

    1.官方网站:knockoutjs.com 2.要dom树加载完毕才能绑定数据 3.ui能实时更新,使用了ko的一个自定义属性:data-bind 4.可以对viewmodel中的属性添加subsci ...

  10. OpenLayers访问WTMS服务及添加Googlemap

    1.访问WMS服务 首先需要发布WMS服务,才能进行地图WMS服务访问.这里不说怎么发布WMS服务,直接看怎么调用,代码如下: 代码 Code highlighting produced by Act ...