es6的generator
let generator_func = function*() {};
let r = 3;
function* ap(a) {
for (let i = 0; i < 3; i++) {
a = a + r;
// yield a a将会作为返回对象的value属性的值。
yield a; // 碰到yield就暂停 保存当前堆栈,返回当前的a
}
// 函数没有return语句 最后一个value为undefined
}
let sum = ap(5);
// next方法:从函数体头部或者上一次停下的地方开始执行,直到遇到下一个yield语句为止。
sum.next(); // {value: 8, done: false}
sum.next(); // {value: 11,done: false}
sum.next(); // {value: 14,done : false}
sum.next(); // {value: undefined, done: true}
co的简单使用
let co = require("co");
let fs = require("fs");
// thunk 偏函数
function read(file) {
return function(fn) {
fs.readFile(file, "utf8", function(err, result) {
if (err) return fn(err);
fn(null, result);
});
};
}
// 使用thunkify写read函数
// let thunkify = require('thunkify');
// let read = thunkify(fs.readFile);
// generator function 只定义不执行
co(function*(next) {
let c = 2;
console.log(c);
/**
* 先执行yield read ,后执行赋值
* 为什么a的值是read()异步返回的数据?
* 因为a的值是gen.next()塞回去的
*/
let a = yield read("demo.js");
console.log(a.length);
let b = yield read("package.json");
console.log(b.length);
});
co的实现
核心思想是想办法递归的调用generator function的next(),直到执行完毕。_next()就是这样的递归方法
function co(fn) {
return function(done) {
let ctx = this;
let gen = fn.call(ctx);
function _next(err, res) {
if (err) res = err;
/**
* it = { value: function(fn){
* fs.readFile(file,'utf8',fn)
* },done: false}
* read返回的函数中的fn 指的是 _next
* .next是用来把结果返回出去并且继续往下执行代码,
* 直到遇到下一个yield
*/
let it = gen.next(res);
if (!it.done) {
// _next用来循环调用.next的
it.value(_next);
}
}
_next();
};
}
为什么异步函数需要封装成thunk的偏函数的形式?
因为我们需要再异步执行完成后,触发_next遍历方法
co接受的generator function 内部执行逻辑和co内部逻辑的执行顺序是什么样的?
- 函数执行到 yield 关键字时,又中断了,执行 read 偏函数,
- it.value(_next) 执行偏函数的返回函数,异步读取文件内容