首先我们知道generator
的内部实现采用了一种类似于协程的方法,即在在函数执行的过程之中遇到yield
关键字时,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next
命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。
对于同步任务而言,我们只需要保证执行完毕即可,不需要确保执行的顺序问题
直接使用for...of...循环 或者使用递归实现
JavaScript 语言对异步编程的实现,就是回调函数。
如果我们能在回调函数之中重新激活generator
中的被冻结的调用栈,不断重复,直至全部调用完成,这样就实现了generator的自动调用
自动执行的关键是,必须有一种机制,自动控制 Generator 函数的流程,接收和交还程序的执行权
对于回调函数的处理主要下面介绍Thunk 函数和promise两种方法
在 JavaScript 语言中通过Thunk函数,把一个具有回调函数包装成一个只接受回调函数作为参数的单参数函数。
例如
fs.readFile(fileName, callback);
// Thunk版本的readFile(单参数版本)
var Thunk = function (fileName) {
return function (callback) {
return fs.readFile(fileName, callback);
};
};
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
我们可以把任何的函数都写成Thunk 函数
function thunkify(fn) {
return function() {
var args = new Array(arguments.length);
var ctx = this;
for (var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
return function (done) {
var called;
args.push(function () {
if (called) return;
called = true;
done.apply(null, arguments);
}); // 确保回调函数只会执行一次
try {
fn.apply(ctx, args);
} catch (err) {
done(err);
}
}
}
};
根据上述的包装后的函数,generator
的自动调用实现如下
function run(fn) {
var gen = fn();
function next(err, data) {
var result = gen.next(data);// 得到当次的执行结果
if (result.done) return;
result.value(next);// 在回调函数中继续调用直到完成
}
next();
}
function* g() {
// ...
}
run(g);
基于promise1的自动执行其实就是在then的回调函数中,不断的调用执行,直到结束
function run(gen){
var g = gen();
function next(data){
var result = g.next(data);
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
}
next();
}
run(gen);
原文:https://www.cnblogs.com/dark-duck/p/14321298.html