async模块简介以及在mysql中的应用
- 2020.04.16
定义
async模块是node中的异步流程控制模块
安装
npm install async
使用
async模块有几个常用的api。
- series(tasks,[callback])
多个函数从上到下依次执行,相互之间没有数据交互.
const task1 = callback => {
	console.log("task1");
	callback(null,"task1");
}
const task2 = callback => {
	console.log("task2");
	callback(null,"task2");
}
    
const task3 = callback => {
	console.log("task3");
	callback(null,"task3");
}
async.series([task1,task2,task3],function(err, result){
	console.log("series");
	if (err) {
		console.log(err);
	}
	console.log(result);
})
/**
 * 1. task1
 * 2. task2
 * 3. task3
 * 4. series
 * 5. [ 'task1', 'task2', 'task3' ]
如果中途发生错误,则将错误传递到回调函数,并停止执行后面的函数
// 修改 task2
const task2 = callback => {
	console.log("task2");
	callback(err,"task2");
}
/**
 * 1. task1
 * 2. task2
 * 3. series
 * 4. err
 * 5. [ 'task1', 'task2']
- parallel(tasks,[callback])
多个函数并行执行,不会等待其他函数,最终把结果存在一个数据中去的,是有先后顺序的
const task1 = callback => {
    console.log("task1", new Date().getTime());
    callback(null,"task1");
}
    
const task2 = callback => {
    console.log("task2", new Date().getTime());
    callback(null, "task2")
}
        
const task3 = callback => {
    console.log("task3", new Date().getTime());
    callback(null,"task3");
}
    
async.parallel([task1,task2,task3],function(err, result){
    console.log("parallel");
    if (err) {
        console.log(err);
    }
    console.log(result);
})
/**
 * 1. task1 1587045158058
 * 2. task2 1587045158060
 * 3. task3 1587045158060
 * 4. parallel
 * 5. [ 'task1', 'task2', 'task3' ]
- waterfall(tasks,[callback]) :瀑布流
依次执行,前一个函数的输出为后一个函数的输入
const task1 = callback => {
    console.log("task1", new Date().getTime());
    callback(null,"task1");
}
    
const task2 = (input, callback) => {
    console.log(input, "task2", new Date().getTime());
    callback(null, "task2")
}
        
const task3 = (input, callback) => {
    console.log(input, "task3", new Date().getTime());
    callback(null,"task3");
}
    
async.waterfall([task1,task2,task3],function(err, result){
    console.log("waterfall");
    if (err) {
        console.log(err);
    }
    console.log(result);
})
/**
 * 1. task1 1587045497048
 * 2. task1 task2 1587045497050
 * 2. task2 task3 1587045497050
 * 3. waterfall
 * 4. task3
 * /
- parallelLimit(tasks,limit,[callback])
和
parallel类似,只是limit参数限制了同时并发执行的个数,不再是无限并发
const task1 = callback => {
  console.log("task1", new Date().getTime());
  setTimeout(()=>callback(null, "task1"), 1000);
}
const task2 = callback => {
  console.log("task2", new Date().getTime());
  setTimeout(()=>callback(null, "task2"), 2000);
}
const task3 = callback => {
  console.log("task3", new Date().getTime());
  setTimeout(()=>callback(null, "task3"), 3000);
}
console.time("parallelLimit执行");
async.parallelLimit([task1, task2, task3], 2, function (err, result) {
  console.log("parallelLimit");
  if (err) {
    console.log(err);
  }
  console.log(result);
  console.timeEnd("parallelLimit执行");
})
/**
 * 1. task1 1587045939489
 * 2. task2 1587045939491
 * 3. task3 1587045940491
 * 4. parallelLimit执行
 * 5. [ 'task1', 'task2', 'task3' ]
 * 6. parallelLimit执行: 4.015s
 */
上面三个函数分别延迟1s、2s、3s执行,总共执行结果为4.015s。
我们设置了并行数量为2,首先执行函数1和2。
1s后函数1和2执行完成,这时函数3开始执行。
3s后函数3执行完毕,总共耗时4.015s。
- compose(fn1,fn2,fn3...)
这个类似中间件,创建一个异步的集合函数,执行的顺序是倒序.前一个fn的输出是后一个fn的输入.有数据交互
const task1 = (m, callback) => {
  console.log("task1", m);
  callback(null, m*2);
}
const task2 = (m, callback) => {
  console.log("task2", m);
  callback(null, m*3);
}
const task3 = (m, callback) => {
  console.log("task3", m);
  callback(null, m*4);
}
const _fn = async.compose(task3, task2, task1);
_fn(2, function (err, result) {
  console.log("compose");
  if (err) {
    console.log(err);
  }
  console.log(result);
})
/**
 * 1. task1 2
 * 2. task2 4
 * 3. task3 12
 * 4. compose
 * 5. 48
 * /
在mysql事务中使用
// mysql.js
var db    = {};
var mysql = require('mysql');
var pool  = mysql.createPool({
    connectionLimit : 10,
    host            : 'localhost',
    user            : 'root',
    password        : '123456',
    database        : 'demo'
})
//获取连接
db.getConnection = function(callback){
	pool.getConnection(function(err, connection) {
		if (err) {
			callback(null);
			return;
		}
		callback(connection);
	});
} 
module.exports = db;
在model中使用
var db = require('./mysql.js');
var async = require('async');
// 事务执行
db.getConnection(function(connection){
  connection.beginTransaction(function(err) {
    if (err) { 
      console.log(err);
      return;
    }
    var task1 = function(callback){
      connection.query(`insert into user (name) values('a')`, function(err, result) {
        if (err) {
          console.log(err);
          callback(err,null);
          return;
        }
        console.log('第一次插入成功!');
        callback(null,result);
      })
    }
    var task2 = function(callback){
      connection.query(`insert into user (name) values('b')`, function(err, result) {
        if (err) {
          console.log(err);
          callback(err,null);
          return;
        }
        console.log('第二次插入成功!');
        callback(null,result);
      })
    }
    var task3 = function(callback){
      connection.query(`insert into user (name) values('c')`, function(err, result) {
        if (err) {
          console.log(err);
          callback(err,null);
          return;
        }
        console.log('第三次插入成功!');
        callback(null,result);
      })
    }
    async.series([task1, task2, task3],function(err,result){
      if (err) {
        console.log(err);
        //回滚
        connection.rollback(function() {
          console.log('出现错误,回滚!');
          //释放资源
          connection.release();
        });
        return;
      }
      //提交
      connection.commit(function(err) {
        if (err) {
          console.log(err);
          return;
        }
          
        console.log('成功,提交!');
        //释放资源
        connection.release();
      });
    })
  });
});
TIP
在使用 async 处理事务的时候经常用到的是series和waterfall两种模式。