前言
针对JS的异步机制,JS社区给出了很多不同的解决方案,Async库便是其中一种,可能也是对于控制异步操作最全面的资源。因为该库提供了70个函数,几乎想所有的运用场景都考虑在内。
parallel
parallel 接受两个参数:
- 第一个参数: 可以是数组或对象, 都可以,区别是输出格式。 多个函数是并行执行,没有前后顺序,不过所有函数执行完毕或者其中任一个返回err非空才会调用第二个参数。
- 第二个参数: 是返回结果,参数,data里面保存上一个参数中多个函数返回的结果。如果任何一个函数返回err非空,会马上调用这个参数,不会等所有函数执行完。
'use strict';
var async = require('async');
console.time('x')
var first = function (cb) {
console.log('i am first!');
setTimeout(() => {
cb(null, 10);
}, 1000);
};
var second = function (cb) {
console.log('i am second!');
setTimeout(() => {
cb(null, 2000);
}, 2000);
};
var end = function (err, data) {
console.log(`err:${err},data:${JSON.stringify(data)}`);
console.timeEnd('x');
}
//async.parallel([first, second], end); //输出: [10,2000]
async.parallel({"fir":first,"sec": second }, end); //输出:{"fir":10,"sec":2000}
series
series 函数和 parallel函数类似,区别是series 第一个参数中的多个函数是并行执行,第一个执行完,才会执行第二个,所以用时会是多个函数运行时间之和,而parallel运行时间取决于最长的那个函数。
'use strict';
var async = require('async');
console.time('x')
var first = function (cb) {
console.log('i am first!');
setTimeout(() => {
cb(null, 10);
}, 1000);
};
var second = function (cb) {
console.log('i am second!');
setTimeout(() => {
cb(null, 2000);
}, 2000);
};
var end = function (err, data) {
console.log(`err:${err},data:${JSON.stringify(data)}`);
console.timeEnd('x');
}
async.series([first, second], end); // 输出:[10,2000]
//async.series({"fir":first,"sec": second }, end); //输出:{"fir":10,"sec":2000}
watchfall
waterfall(tasks, [callback])
series函数并没有给出传递参数给下一个函数的功能,如果想并行执行同时把上一个函数callback结果传给下一个函数,需要用waterfall。
(多个函数依次执行,且前一个的输出为后一个的输入)按顺序依次执行多个函数。每一个函数产生的值,都将传给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将传给waterfall最终的callback。
对于学过了js回调机制的小伙伴,waterfall是比较容易理解的,个人的理解就是,waterfall中传入的函数数组tasks中,后一个函数为前一个函数的回调,使用cb(null,args),这样的形式调用下一个函数,如果出现异常,则直接使用cb(new Error(“错误的信息”))这样的方式来捕捉异常,并调用最终的回调函数来处理,在这种情况下,出现异常的函数后面那些函数,将不再继续执行,测试代码如下:
'use strict';
var async = require('async');
console.time('x')
var first = function (cb) {
console.log('i am first!');
setTimeout(() => {
cb(null, 10);
}, 1000);
};
var second = function (data,cb) {
console.log('i am second!,data:',JSON.stringify(data));
setTimeout(() => {
cb(null, 2000);
}, 2000);
};
var end = function (err, data) {
console.log(`err:${err},data:${JSON.stringify(data)}`);
console.timeEnd('x');
}
async.waterfall([first, second], end); //输出 2000
官方文档:
https://github.com/caolan/async/blob/v1.5.2/README.md#waterfall
map,mapLimit
map(coll, iteratee, callbackopt)
mapLimit(coll, limit, iteratee, callbackopt)
whilst(test, iteratee, callbackopt)
Repeatedly call iteratee, while test returns true. Calls callback when stopped, or an error occurs.
"use strict";
var async = require("async");
var index = 0;
var winChips = {
"0": 100,
"1": -100,
"2": 3,
"3": 4,
};
var keys = Object.keys(winChips);
async.whilst(
function (cb) {
cb(null, index < keys.length);
}, // 如果第一个函数写成: function () {return index < keys.length;}, 下一个函数不会执行,什么都不执行,也不会报错
function (cb) {
console.log(`index:${index},chips:${ winChips[index++]}`);
cb(null, index);
},
function (err, data) {
console.log(`err:${err},data:${data}`);
}
);
之前关于test部分的写法是:
function () { return count < 5; }, 这样写,导致后面iter函数并不会执行,直接跳过这个函数。在这个函数栽过跟头。