Because of the JavaScript language async feature, callback functions are used when using node. js to perform many operations, including accessing the database. If the business logic in the code is a little more complicated, and the callback layer is nested, then the code is easy to get into callback Hell, which is a mental torment for people who write code or who read code.
For example, a transaction operation for MySQL, insert a posts and insert a log:
vartitle =' It is a new post '; Connection.begintransaction ( function(err) { if(ERR) {ThrowErr } connection.query (' INSERT into posts SET title=? ', title, function(err, result) { if(ERR) {returnConnection.rollback ( function() { ThrowErr }); }varLog =' Post '+ Result.insertid +' added '; Connection.query (' INSERT into log SET data=? ', log, function(err, result) { if(ERR) {returnConnection.rollback ( function() { ThrowErr }); } connection.commit ( function(err) { if(ERR) {returnConnection.rollback ( function() { ThrowErr }); } console.log (' success! '); }); }); });});
The above very simple business logic has been recalled several layers, if a little more complex, then the code will not be able to look directly.
In order to prevent the large pits where multiple layers of nested callbacks occur, async.js can be used to solve this problem. The following is an introduction to the use of MySQL database with async.js operation.
Async.each BULK Insert
Assuming that the requirement is to insert multiple data into the log table and ultimately return the execution result, you can use the Async.each function:
varSqls = ["INSERT into log SET data= ' data1 '","INSERT into log SET data= ' data2 '","INSERT into log SET data= ' data3 '"];async.each (Sqls, function(item, callback) { //iterate through each SQL and executeConnection.query (Item, function(err, results) { if(ERR) {///exception after calling callback and passing in ErrCallback (ERR); }Else{Console.log (item +"Successful Execution");callback is also called when execution is complete, no parameters requiredCallback (); } });}, function(err) { //callback after all SQL execution is complete if(ERR) {Console.log (ERR); }Else{Console.log ("SQL Full execution succeeded"); }});
Async.each does not guarantee the execution of a successful SQL statement and then executes the next one, so if one execution fails, it does not affect the execution of other statements.
Async.eachseries Batch Inserts sequentially
You can use the Eachseries function if you want to implement the next statement in the array before executing the last statement of the successful execution:
varSqls = ["INSERT into log SET data= ' data1 '","INSERT into log SET data= ' data2 '","INSERT into log SET data= ' data3 '"];async.eachseries (Sqls, function(item, callback) { //iterate through each SQL and executeConnection.query (Item, function(err, results) { if(ERR) {///exception after calling callback and passing in ErrCallback (ERR); }Else{Console.log (item +"Successful Execution");callback is also called when execution is complete, no parameters requiredCallback (); } });}, function(err) { //callback after all SQL execution is complete if(ERR) {Console.log (ERR); }Else{Console.log ("SQL Full execution succeeded"); }});
Async.eachseries guarantees the execution order of SQL, and when one of them executes the exception, it does not proceed to the next one.
Async.foreachof get query results for multiple SELECT statements
Async.foreachof is similar to Async.each, where the difference is that the object type parameter can be received and the key of each entry traversed to the second parameter callback function is passed in, which is more suitable for executing the query statement in bulk and returning the result:
varSqls = {table_a:"SELECT COUNT (*) from table_a", Table_b:"SELECT COUNT (*) from Table_b", Table_c:"SELECT COUNT (*) from Table_c"};//For storing query resultsvarCounts = {};async.foreachof (SQLS, function(value, key, callback) { //iterate through each SQL and executeConnection.query (Value, function(err, results) { if(ERR) {Callback (ERR); }Else{Counts[key] = results[0][' Count (*) ']; Callback (); } });}, function(err) { //callback after all SQL execution is complete if(ERR) {Console.log (ERR); }Else{Console.log (counts); }});
Operation Result:
{table_a:26, table_b:3, Table_c:2}
Async.map simplifies getting query results for multiple SELECT statements
The code above Async.foreachof gets the query results for multiple SELECT statements can be simplified using the ASYNC.MAP function:
var sqls = {table_a: " SELECT COUNT (*) from table_a ", Table_b: " SELECT COUNT (*) from Table_b " /span>, Table_c: "SELECT COUNT (*) from Table_c" };async.map (Sqls, function (item, callback) { connection.query (item, function (err, results) { callback (err, Results[0 ][ ' count (*) ' ]); }), function (err, Results) { if (Err) {Console.log (err); } else {console.log (results); }});
Operation Result:
{table_a:26, table_b:3, Table_c:2}
Async.series perform multiple tasks sequentially
One of the most practical features of async.js is Process control. Back to the beginning of this article, the open transaction execution Insert example, each step requires a successful execution of the previous step to execute, it is easy to fall into the callback pit. The following practical async.series function optimizes process control to make the code more elegant:
vartitle =' It is a new post ';//used to save the auto-generated ID after the posts insert succeedsvarPostID =NULL;//function array, a list of tasks that need to be performed, each function has a parameter callback function and is calledvartasks = [ function(callback) { //Open transactionConnection.begintransaction ( function(err) {Callback (ERR); });}, function(callback) { //Insert postsConnection.query (' INSERT into posts SET title=? ', title, function(err, result) {PostID = Result.insertid; Callback (ERR); });}, function(callback) { //Insert Log varLog =' Post '+ PostID +' added '; Connection.query (' INSERT into log SET data=? ', log, function(err, result) {Callback (ERR); });}, function(callback) { //Commit a transactionConnection.commit ( function(err) {Callback (ERR); });}]; Async.series (Tasks, function(err, results) { if(ERR) {Console.log (ERR); Connection.rollback ();//Error occurred transaction rollback} connection.end ();});
Async.waterfall perform multiple tasks sequentially and the next task to get the results of the previous task
The above uses async.series to perform multiple tasks sequentially, but in many cases a task needs to use the relevant data of the previous task, such as inserting a piece of data into the posts table, the ID will be automatically generated, the next insert log will use this ID, if you use the Async.series function to define a Variable var postId
to store this ID, you can use Async.waterfall instead of async.series.
vartitle =' It is a new post ';vartasks = [ function(callback) {Connection.begintransaction ( function(err) {Callback (ERR); });}, function(callback) {Connection.query (' INSERT into posts SET title=? ', title, function(err, result) {Callback (err, Result.insertid);//The generated ID is passed to the next task});}, function(Insertid, callback) { //Receive the ID generated by the previous task varLog =' Post '+ Insertid +' added '; Connection.query (' INSERT into log SET data=? ', log, function(err, result) {Callback (ERR); });}, function(callback) {Connection.commit ( function(err) {Callback (ERR); });}]; Async.waterfall (Tasks, function(err, results) { if(ERR) {Console.log (ERR); Connection.rollback ();//Error occurred transaction rollback} connection.end ();});
Async.series getting results from multiple SQL
//Tasks is an objectvartasks = {table_a: function(callback) {Connection.query (' SELECT COUNT (*) from table_a ', function(err, result) {Callback (Err, result[0][' Count (*) ']);//Pass results to callback}); }, Table_b: function(callback) {Connection.query (' SELECT COUNT (*) from Table_b ', function(err, result) {Callback (Err, result[0][' Count (*) ']); }); }, Table_c: function(callback) {Connection.query (' SELECT COUNT (*) from Table_c ', function (err, result) {Callback (Err, result[0][' Count (*) ']); }); }};async.series (Tasks, function(err, results) { if(ERR) {Console.log (ERR); }Else{Console.log (results); } connection.end ();});
Operation Result:
{table_a:26, table_b:3, Table_c:2}
These are some of the examples that are often used in the Async.js operations database, and it is no longer necessary to worry about the hole in the async callback. Async.js can be used not only for database operations, but also for other places where asynchronous callback functions are used, such as file reading and writing, this article simply introduces the basic usage of async.js using database operations as an example, and it can be applied to other places where it is needed. In addition to the several functions described above, Async.js also provides some other useful functions, which can be used flexibly in reference to documents.
async.js resolves the node. js Operation MySQL Callback Tai Hang