js异步控制流及async实现细节分析_前端开发者_网站前端开发

js异步控制流及async实现细节分析(2) 4. map / filter / reject在async中, each系列的方法一共有12个: each / forEacheachOf / forEachOfeachLimit / forEachLimiteachOfLimit / forEachOfLimiteachSeries / forEachSerieseachOfSeries / forEachOfSeries这些方法的回调函数签名为 callback(err), 只有一个参数表示是否出错, 因此无法收集到每个异步任务的结果。 如果我们希望如下调用: map(files, fs.readFile, function (err, result) {
if (err) {
throwerr;
}
result.forEach(data=>console.log(data.toString()));
});
1 2 3 4 5 6 map(files, fs.readFile, function (err, result) {
if (err) {
throwerr;
}
result.forEach(data=>console.log(data.toString()));
});
考虑到对于数组而言, 可以通过 forEach 来实现map功能, 例如:
function arrayMap(arr, fn) {
varresult= [];
arr.forEach((val,key)=>result.push(fn(val,key,arr)));
returnresult;
}
1 2 3 4 5
function arrayMap(arr, fn) {
varresult= [];
arr.forEach((val,key) =>result.push(fn(val,key,arr)));
returnresult;
}
因此, 在这里, 可以通过 async.eachOf 来实现 map, 代码逻辑如下:
function map(arr, fn, callback) {
calback=once(callback||function(){});
arr=arr|| [];
varresult=Array.isArray(arr) ? [] :{};
async.eachOf(arr,function(val,key,callback){
fn(val,function(err,data){
result[key] =data;
callback(err);
});
},function(err){
callback(err,result);
});
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14
function map(arr, fn, callback) {
calback=once(callback||function(){});
arr=arr|| [];
varresult=Array.isArray(arr) ? [] :{};
async.eachOf(arr,function(val,key,callback){
fn(val,function(err,data){
result[key] =data;
callback(err);
});
},function(err){
callback(err,result);
});
}
同样, mapLimit 和 mapSeries 也可以通过类似的方式实现。 filter功能的实现也是类似的方式, 例如我们希望过滤出所有存在的文件, 期望的调用方式如下: 由于fs.exists已经废弃, 否则可以直接filter(files, fs.exists, callback) filter(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (err, result) {
if (err) {
throwerr;
}
console.log(result);
});
1 2 3 4 5 6 7 8 9 10 11 由于fs.exists已经废弃, 否则可以直接filter(files, fs.exists, callback) filter(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (err, result) {
if (err) {
throwerr;
}
console.log(result);
});
filter 的实现如下:
function filter(arr, fn, callback) {
calback=once(callback||function(){});
arr=arr|| [];
varresult= [];
async.eachOf(arr,function(val,key,callback){
fn(val,function(v){
if (v) {
result.push(val);
}
callback();
});
},function(err){
callback(err,result);
});
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
function filter(arr, fn, callback) {
calback=once(callback||function(){});
arr=arr|| [];
varresult= [];
async.eachOf(arr,function(val,key,callback){
fn(val,function(v){
if (v) {
result.push(val);
}
callback();
});
},function(err){
callback(err,result);
});
}
同样, filterLimit 和 filterSeries 也可以通过类似的方式实现。 而 reject 的实现与 filter 几乎一样, 除了判断条件不同之外, 在async中的源码如下:
function _reject(eachfn, arr, iterator, callback) {
_filter(eachfn,arr,function(value,cb){
iterator(value,function(v){
cb(!v);
});
},callback);
}
async.reject = doParallel(_reject);
async.rejectLimit = doParallelLimit(_reject) 1 2 3 4 5 6 7 8 9
function _reject(eachfn, arr, iterator, callback) {
_filter(eachfn,arr,function(value,cb){
iterator(value,function(v){
cb(!v);
});
},callback);
}
async.reject = doParallel(_reject);
async.rejectLimit = doParallelLimit(_reject) 5. some / every / detectsome 实现逻辑如下:
function some(arr, fn, cb) {
async.eachOf(arr,function(val,key,callback){
如果cb为null, 说明之前已经有某个任务的结果为truthy因此直接执行callback, 相当于跳过该任务
if (!cb) {
returncallback();
}
fn(val,function(v){
如果该任务返回truthy, 则调用最终的回调cb(true) 然后将cb置为null, 表示已经有了truthy值, 从而阻止后续任务的继续执行
if (cb&&!!v) {
cb(true);
cb=null;
}
callback();
});
},function(err){
此时所有任务已经执行完毕, 如果cb仍然不为null说明所有的任务都返回了falsy, 因此最终为cb(false) if (cb) {
cb(false);
}
});
}
example some(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (val) {
console.log(val);
});
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
function some(arr, fn, cb) {
async.eachOf(arr,function(val,key,callback){
如果cb为null, 说明之前已经有某个任务的结果为truthy因此直接执行callback, 相当于跳过该任务
if (!cb) {
returncallback();
}
fn(val,function(v){
如果该任务返回truthy, 则调用最终的回调cb(true) 然后将cb置为null, 表示已经有了truthy值, 从而阻止后续任务的继续执行
if (cb&&!!v) {
cb(true);
cb=null;
}
callback();
});
},function(err){
此时所有任务已经执行完毕, 如果cb仍然不为null说明所有的任务都返回了falsy, 因此最终为cb(false) if (cb) {
cb(false);
}
});
}
example some(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (val) {
console.log(val);
});
every 与此类似, 实现逻辑如下:
function every(arr, fn, cb) {
async.eachOf(arr,function(val,key,callback){
如果cb为null, 说明之前已经有某个任务的结果为falsy因此直接执行callback, 相当于跳过该任务
if (!cb) {
returncallback();
}
fn(val,function(v){
如果该任务返回falsy, 则调用最终的回调cb(false) 然后将cb置为null, 表示已经有了falsy值, 从而阻止后续任务的继续执行
if (cb&&!v) {
cb(false);
cb=null;
}
callback();
});
},function(err){
此时所有任务已经执行完毕, 如果cb仍然不为null说明所有的任务都返回了truthy, 因此最终为cb(true) if (cb) {
cb(true);
}
});
}
example every(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (val) {
console.log(val);
});
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
function every(arr, fn, cb) {
async.eachOf(arr,function(val,key,callback){
如果cb为null, 说明之前已经有某个任务的结果为falsy因此直接执行callback, 相当于跳过该任务
if (!cb) {
returncallback();
}
fn(val,function(v){
如果该任务返回falsy, 则调用最终的回调cb(false) 然后将cb置为null, 表示已经有了falsy值, 从而阻止后续任务的继续执行
if (cb&&!v) {
cb(false);
cb=null;
}
callback();
});
},function(err){
此时所有任务已经执行完毕, 如果cb仍然不为null说明所有的任务都返回了truthy, 因此最终为cb(true) if (cb) {
cb(true);
}
});
}
example every(files, function (file, callback) {
fs.access(file,function(err){
callback(err?false:true);
});
}, function (val) {
console.log(val);
});
detect 返回的是第一个执行为truthy的值, 与 some 非常类似, 只需要将 cb(true) 和 cb(false) 分别替换为 cb(val) 和 cb(undefined) 即可。 6. reduce / reduceRightreduce 和 reduceRight 主要通过 async.eachOfSeries 来实现, 注意reduce相关的只有一个series版本, 即只有串行执行的版本, 因为涉及到reduce的操作往往是要依赖于上一次操作的返回值, 因此不能够并行执行。
赞(0)
前端开发者 » js异步控制流及async实现细节分析_前端开发者_网站前端开发
64K

评论 抢沙发

评论前必须登录!