1.async
https://github.com/caolan/async/blob/v1.5.2/README.md#times
https://github.com/bsspirit/async_demo 一些demo
var mysql = require('mysql');
var conn = mysql.createConnection({
host: 'localhost',
user: 'nodejs',
password: 'nodejs',
database: 'nodejs',
port: 3306
});
conn.connect();
var insertSQL = 'insert into t_user(name) values("conan"),("fens.me")';
var selectSQL = 'select * from t_user limit 10';
var deleteSQL = 'delete from t_user';
var updateSQL = 'update t_user set name="conan update" where name="conan"';
//delete
conn.query(deleteSQL, function (err0, res0) {
if (err0) console.log(err0);
console.log("DELETE Return ==> ");
console.log(res0);
//insert
conn.query(insertSQL, function (err1, res1) {
if (err1) console.log(err1);
console.log("INSERT Return ==> ");
console.log(res1);
//query
conn.query(selectSQL, function (err2, rows) {
if (err2) console.log(err2);
console.log("SELECT ==> ");
for (var i in rows) {
console.log(rows[i]);
}
//update
conn.query(updateSQL, function (err3, res3) {
if (err3) console.log(err3);
console.log("UPDATE Return ==> ");
console.log(res3);
//query
conn.query(selectSQL, function (err4, rows2) {
if (err4) console.log(err4);
console.log("SELECT ==> ");
for (var i in rows2) {
console.log(rows2[i]);
}
});
});
});
});
});
//conn.end();
//改进
var mysql = require('mysql');
var async = require('async');
var conn = mysql.createConnection({
host: 'localhost',
user: 'nodejs',
password: 'nodejs',
database: 'nodejs',
port: 3306
});
var sqls = {
'insertSQL': 'insert into t_user(name) values("conan"),("fens.me")',
'selectSQL': 'select * from t_user limit 10',
'deleteSQL': 'delete from t_user',
'updateSQL': 'update t_user set name="conan update" where name="conan"'
};
var tasks = ['deleteSQL', 'insertSQL', 'selectSQL', 'updateSQL', 'selectSQL'];
async.eachSeries(tasks, function (item, callback) {
console.log(item + " ==> " + sqls[item]);
conn.query(sqls[item], function (err, res) {
console.log(res);
callback(err, res);
});
}, function (err) {
console.log("err: " + err);
});
1. series(tasks, [callback]) (多个函数依次执行,之间没有数据交换)
解决问题
step1(function(err, v1) {
step2(function(err, v2) {
step3(function(err, v3) { // do somethig with the err or values v1/v2/v3
}
}
});
var async = require('async')
async.series([
function(cb) { step1(function(err,v1) {
// do something with v1
cb(err, v1);
}),
function(cb) { step2(...) },
function(cb) { step3(...) }
], function(err, values) {
// do somethig with the err or values v1/v2/v3
});
2. parallel(tasks, [callback]) (多个函数并行执行)
如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它未执行完的函数的值不会传到最终数据,但要占个位置。
同时支持json形式的tasks,其最终callback的结果也为json形式。
示例代码:
async.parallel([
function(cb) { t.fire('a400', cb, 400) },
function(cb) { t.fire('a200', cb, 200) },
function(cb) { t.fire('a300', cb, 300) }
], function (err, results) {
log('1.1 err: ', err); // -> undefined
log('1.1 results: ', results); // ->[ 'a400', 'a200', 'a300' ]
});
async.parallel([
function(cb) { log('1.2.1: ', 'start'); t.fire('a400', cb, 400) }, // 该函数的值不会传给最终callback,但要占个位置
function(cb) { log('1.2.2: ', 'start'); t.err('e200', cb, 200) },
function(cb) { log('1.2.3: ', 'start'); t.fire('a100', cb, 100) }
], function(err, results) {
log('1.2 err: ', err); // -> e200
log('1.2 results: ', results); // -> [ , undefined, 'a100' ]
});
3. waterfall(tasks, [callback]) (多个函数依次执行,且前一个的输出为后一个的输入)
seires相似,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将传给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将传给waterfall最终的callback。
async.waterfall([
function(cb) { log('1.1.1: ', 'start'); cb(null, 3); },
function(n, cb) { log('1.1.2: ',n); t.inc(n, cb); },
function(n, cb) { log('1.1.3: ',n); t.fire(n*n, cb); }
], function (err, result) {
log('1.1 err: ', err); // -> null
log('1.1 result: ', result); // -> 16
});
二、promise解决
fs.readFile("test.txt",function(err,data){
if(!err){
console.log(data);
}else{
console.error(err);
}
});
我们可以把 fs.readFile函数封装为 promise风格的函数,如下:
var preadFile = function(file){
fs.readFile(file,function(err,data){
var deferred = Q.defer();
if(!err){
deferred.resolve(data);
}else{
deferred.reject(err);
}
return deferred.promise;
});
}
//then 的第一个参数是正确处理函数,第二个参数是错误处理函数
preadFile("test.txt").then(console.log,console.error);
1.各个回调函数顺序传递数据:
var fun1 = function (data,cb) {
cb(null,data+" fun1");
}
var fun2 = function (data,cb) {
cb(null,data+" fun2");
}
var fun3 = function (data,cb) {
cb(null,data+" fun3");
}
function main(data,cb){
fun1(data,function(err,data){
if(!err){
fun2(data,function(err,data){
if(!err){
fun3(data,cb);
}else{
cb(err);
}
});
}else{
cb(err);
}
});
}
var fun1 = function (data,cb) {
cb(null,data+" fun1");
}
var fun2 = function (data,cb) {
cb(null,data+" fun2");
}
var fun3 = function (data,cb) {
cb(null,data+" fun3");
}
function main(data,cb){
fun1(data,function(err,data){
if(!err){
fun2(data,function(err,data){
if(!err){
fun3(data,cb);
}else{
cb(err);
}
});
}else{
cb(err);
}
});
}
解决方法
var Q = require("q");
var fun1 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun1");
return deferred.promise;
}
var fun2 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun2");
return deferred.promise;
}
var fun3 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun3");
return deferred.promise;
}
function main(data,cb){
fun2("test")
.then(fun3)
.then(fun4)
.done(function(data){
cb(null,data);//ok 获得的最终数据为 --->"test fun1 fun2 fun3"
},function(err){
cb(err);//failed
});
}
2.收集各个回调函数产生的数据:有时候我们需要执行很多回调函数,然手把这个回调函数的数据一齐传递给一个函数处理,此时我们可以使用 all 和 spread 方法,参看如下代码:
var Q = require("q");
var fun1 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun1");
return deferred.promise;
}
var fun2 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun2");
return deferred.promise;
}
var fun3 = function (data) {
var deferred = Q.defer();
deferred.resolve(data+" fun3");
return deferred.promise;
}
Q.all([
fun2("test1"),fun3("test2"),fun4("test3")
]).spread(function(){
console.log(arguments);//获得的参数为('test1 fun1', 'test2 fun2', 'test3 fun3' )
});