为了使多个异步函数按顺序执行,我们在书写异步函数的时候,必须要在函数体里加上某些能标记函数执行完毕的语句,用于提示下面的函数开始进行。
假设原始的异步函数如下:
var func = function(arg) {
setTimeout(() => {
console.log(arg);
}, 100);
};
如果需要多个这样的函数顺序执行,就必须对其进行改写,让机器知道这个函数什么时候执行完毕
常见的方法有下面两种
- callback函数
每个接受callback函数的异步函数都能用Thunk改写,实际使用中可以使用thunkify模块
var func = function(arg, callback) {
setTimeout(() => {
console.log(arg);
var err;
var data;
callback(err, data);
}, 100);
};
//Thunk生成器
const Thunk = function(fn) {
return function (...args) {
return function (callback) {
return fn.call(this, ...args, callback);
}
};
};
//控制流程的generator
var generator = function* (){
var f1 = yield Thunk(func1)(arg1);
var f2 = yield Thunk(func2)(arg2);
// ...
var fn = yield Thunk(funcN)(arg3);
};
function run(generator) {
var iter = generator();
function next(err, data) {
var result = iter.next(data);
//result是{value:[Function],done:...}的对象
if (result.done) return;
result.value(next);
//result.value是Thunk最内层的函数,接受回调函数
//这里实际上是把next作为每个函数的回调函数,用于标识函数是否结束
}
next();
}
run(generator);//自动执行
- Promise
Promise是ES6里面的对象,使用这个对象进行多个异步操作的流程管理显得很方便,使用Co模块可以方便的进行异步操作的管理
var func = function(last) {
return new Promise((resolve, reject)=>{
setTimeout(() => {
console.log(arg);
var err;
var data;
resole(data); //或reject(err)
}, 100);
});
};
//控制流程的generator
var generator = function* (){
var f1 = yield func1(arg);
var f2 = yield func2(arg2);
// ...
var fn = yield funcN(arg3);
};
function run(generator){
var iter = generator();
function next(data){
var result = iter.next(data);
//result是{value:[Promise],done:...}的对象
if (result.done) return result.value;
result.value.then(function(data){
next(data);
});
//这里用promise标识每个函数的结束
}
next();
}
run(gen);