不定量异步请求的串行处理
串行处理不定数量的异步请求,并且这些异步请求有前后依赖关系,我的方案如下:
es6中引入了generator函数,它是用来处理异步任务的。调用generator函数会返回一个iterator对象,通过iterator的方法控制generator的内部执行,达到执行挂起、执行恢复的效果。
第一步:将一个拥有回调函数的异步请求函数封装为一个只需要传回调函数的单参数函数(函数的curring,如果我没记错),代码如下:
//这是一个正常的异步函数
mysql.query('select...', callback)
//单参数版本
const thunk = function (queryStr) {
return function (callback) {
return mysql.query(queryStr, callback);
}
};
const thunkQuery = thunk('select...');
第二步:定义一个Generator函数
const queryArr = ['select...', 'select...', ...];
function* gen(queryArr, limit) {
let i = 0,
length = queryArr.length,
results = [];
do {
// 此处可以对异步任务的依赖关系进行处理
const result = yield thunk(queryArr[i]);
Array.prototype.push.apply(results, result);
i += 1;
} while (i < length && results.length < limit )//这里可以加其他让Generator停下来的条件
return results;
}
第三步:定义一个控制Generator执行流程的管理器
function autoRun(fn){
const iterator = fn();
function handler(err, data) {
if (err) {
iterator.throw(err);
} else {
iterator.next(data);
}
}
iterator.next(handler);
}
第三步的关键点是每一步的异步请求结束后,将结果返回给genrator,由genrator管理请求的结果数据,并且generator再次返回一个只需传回调函数的单参数请求函数
2020年4月8日,重读以前的文章发现有一些错误,特将上面错误修正。并且在ES2017的推出以及Babel和Traceur等转译工具的广泛使用。现在,异步串行处理有了更好的解决方案,通过async函数,可以用同步的写法处理异步任务。将上面的例子进行改写
第一步:将拥有回调函数的异步函数转化为一个返回promise对象的函数,现在大部分异步任务都提供了peomise接口,为了让一些老旧API做到兼容promise,因此做个简单展示
mysql.query = function(queryStr) {
return new Promise(function(resolve, reject) {
mysql.query(queryStr, function (err, data) {
if (err) {
return reject(err);
}
return sesolve(data);
})
});
}
第二步使用asyn函数,以同步写法描述异步串行任务,在每个返回promise的异步任务前,添加await关键字
const queryStr = ['select...', 'select...', ...];
(async function() {
let i = 0,
length = queryArr.length,
results = [];
do {
// 此处可以对异步任务的依赖关系进行处理
const result = await mysql.query(queryArr[i]);
Array.prototype.push.apply(results, result);
i += 1;
} while (i < length && results.length < limit )
})()