Because of the JavaScript language async feature. A callback function is used when you use node. js to run very many operations, including an Access database. Assume that the business logic in the code is slightly more complex, with a callback layer nested. So the code is very easy to enter callback Hell, regardless of the code of the person or read the code of the people, is a mental torture.
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, assuming a little more complex, then the code will not be able to look directly.
In order to prevent the large pits with multiple layers of nested callbacks, async.js can be used to solve the problem. To come down and introduce the use of MySQL database async.js combined operation.
Async.each BULK Insert
Suppose the requirement is to insert more than one data into the log table. Finally, you can return to the run result and 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) { //Traverse each SQL and runConnection.query (Item, function(err, results) { if(ERR) {///exception after calling callback and passing in ErrCallback (ERR); }Else{Console.log (item +"Run successfully");//Call callback after running, no parameters requiredCallback (); } });}, function(err) { //All SQL callback after run complete if(ERR) {Console.log (ERR); }Else{Console.log ("SQL all runs successfully"); }});
Async.each does not guarantee a successful SQL statement before running the next one. So suppose that there is a run failure that does not affect the operation of other statements.
Async.eachseries Batch Inserts sequentially
Assuming that you want to implement the previous statement of running successfully and then start running the next statement in the array, you can use the Eachseries function:
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) { //Traverse each SQL and runConnection.query (Item, function(err, results) { if(ERR) {///exception after calling callback and passing in ErrCallback (ERR); }Else{Console.log (item +"Run successfully");//Call callback after running, no parameters requiredCallback (); } });}, function(err) { //All SQL callback after run complete if(ERR) {Console.log (ERR); }Else{Console.log ("SQL all runs successfully"); }});
Async.eachseries guarantees the order in which SQL is run. And when one of them runs abnormally. You will not continue to run the next article.
Async.foreachof get query results for multiple SELECT statements
Async.foreachof similar to Async.each, the difference is the ability to receive object type parameters. It also passes in the second parameter callback function the key of each item that is traversed, more suitable to run the query statement in bulk and return 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) { //Traverse each SQL and runConnection.query (Value, function(err, results) { if(ERR) {Callback (ERR); }Else{Counts[key] = results[0][' Count (*) ']; Callback (); } });}, function(err) { //All SQL callback after run 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 that Async.foreachof gets the query results of 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 running multiple tasks sequentially
One of the most useful features of async.js is Process control. Go back to the example of the open transaction running insert from the beginning of this article. Each step needs to run successfully after a successful operation, very easy to fall into the callback pit.
Here are some useful async.series functions to optimize process control to make your code more elegant:
vartitle =' It is a new post ';//Used to save self-generated IDs when posts is successfully insertedvarPostID =NULL;//function array, the list of tasks that need to be run, each function has a parameter callback function and to invokevartasks = [ 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 run multiple tasks sequentially and the next task can get the results of the previous task
The above uses Async.series to run multiple tasks sequentially. However, in very many cases when running a task need to use the relevant data of the previous task, such as inserting a piece of data into the posts table, will be actively generated ID, the next insert log will use this ID, assuming that the use of async.series function will need 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(); // 错误发生事务回滚 } 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 by the Async.js operations database, and it is no longer necessary to worry about asynchronous callback pits. Async.js can be used not only for database operations, but for other places where asynchronous callback functions are used. such as file read and write, this article but through the database operation as an example to introduce the basic use of Async.js method. It can also 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 that can be used flexibly in the documentation.
async.js resolves the node. js Operation MySQL Callback Tai Hang