关于es6的generator函数
generator含义及用法
generator(生成器)是ES6标准引入新的数据类型, 一个generator看上去像一个函数,但可以返回多次。
-
generator使用
function*
定义,除了return语句外,还可以用yield返回多次。 -
next()
方法返回一个对象{value: x, done: true/false}
,其中value属性表示yield关键词后面表达式的值,done属性表示是否遍历结束。generator生成器通过next和yield的配合实现流程控制。next方法还可以接受参数,向generator内输入数据 -
throw('error')
方法来抛出异常。当出现异常后,迭代中止,再次执行gen.next()时,将返回{value: undefined, done: true};
下面的列子中使用 function *gen(){...}
定义了一个generator函数,在函数中使用了两个yield和return,就是说这个函数可以返回三次,即每次调用next()
方法,函数就执行到yield语句的地方,然后暂停。
function* gen(){
yield 'hello';
yield 'world';
return true;
}
var iter = gen();
var a = iter.next();
console.log(a);
var b = iter.next();
console.log(b);
var c = iter.next();
console.log(c);
使用generator函数解决异步回调问题
在这个例子中,generator函数中,yield后面返回的都是Promise,也就是说next()方法返回的value也是Promise,可以像处理promise的方式处理next()方法的返回值value,加上then回调处理。
function* gen(){
yield $.get('http://v.beihaoyun.com/api/hosp/doctor/list?page=1&pageSize=4&status=1');
yield $.get('http://v.beihaoyun.com/api/article/post/list?page=1&pageSize=4&article_category_id=10');
yield $.get('http://v.beihaoyun.com/api/question/list2?page=1&pageSize=4&top_id=0&add_answer=true');
}
var g = gen();
g.next().value.then(res=>{
console.log(res)
g.next(res).value.then(resp=>{
console.log(resp)
g.next(resp).value.then(res2=>{
console.log(res2)
})
})
})
上面的例子使用了手动调用next方法层层添加回调函数,下面写一个自动执行器
function* gen(){
let a = yield $.get('http://v.beihaoyun.com/api/hosp/doctor/list?page=1&pageSize=4&status=1');
let b = yield $.get('http://v.beihaoyun.com/api/article/post/list?page=1&pageSize=4&article_category_id=10');
let c = yield $.get('http://v.beihaoyun.com/api/question/list2?page=1&pageSize=4&top_id=0&add_answer=true');
console.log(a,b,c)
}
function run(gen){
var g = gen();
function next(data){
var result = g.next(data);
if(result.done)return result.value;
result.value.then(res=>{
next(res);
})
}
next();
}
run(gen)
co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行。https://github.com/tj/co
co 函数库可以让你不用编写 Generator 函数的执行器。
var co = require('co');
co(gen);
co 函数库的源码https://github.com/tj/co/blob/master/index.js
实现co框架
function co(gen) {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(gen.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(gen.throw(value));
} catch (e) {
reject(e);
}
};
var step = (result) => {
result.done ? resolve(result.value)
: Promise.resolve(result.value).then(fulfilled, rejected);
};
step((gen = gen()).next());
});
}
co(function*(){
let a = yield $.get('http://v.beihaoyun.com/api/hosp/doctor/list?page=1&pageSize=4&status=1');
console.log(a)
let b = yield $.get('http://v.beihaoyun.com/api/article/post/list?page=1&pageSize=4&article_category_id=10');
console.log(b)
let c = yield $.get('http://v.beihaoyun.com/api/question/list2?page=1&pageSize=4&top_id=0&add_answer=true');
console.log(c)
})
参考资料
- http://www.ruanyifeng.com/blog/2015/05/thunk.html
- http://www.ruanyifeng.com/blog/2015/05/co.html
- https://github.com/tj/co
- https://cnodejs.org/topic/5ab50b420b13e3ad6954cdd6