1.node.js considerations when encountering "loop + Async"

Source: Internet
Author: User

Original: 50585073

Since the use of node. js, what has been bothering me is async. Always encounter some, do not follow the code to write the order of the situation, although the information on the Internet a lot. But there is little to find that can be easily understood. Here we find a case study of cyclic + asynchronous processing precautions. For everyone's reference.

Characteristics of Nodejs

The biggest feature of Nodejs is that everything is event-based, which causes everything to be asynchronous. Nodejs speed, the principle of the same as Nginx, they are through the event callback to handle the request, resulting in the entire process, will not block Nodejs, so it can handle a large number of requests at the same time, and this advantage in your request is IO-intensive case, Performance is particularly prominent. The following example simply illustrates the process of NODEJS based on asynchronous events:

var function (req,res) {    = ' SELECT gid,name,image_url,price,create_time,describes,selluid from goods WHERE status=? LIMIT?,? ' ;    Connection.query (SQL, [function(err, rows, fields) {        ifthrow  Err;        Console.log ("output: The result of handling database operations here");    });     Console.log ("Output: This is the statement after database operation");};
 

Programmers who have used Nodejs should be able to easily know that the output of the function is:

Output: This is the statement output after the database operation: The result of processing the database operation here

The reason is simple, the above query statement is not immediately executed, but into the queue to be executed immediately return, and then continue to execute the following statement, when the database operation is finished, an event will be triggered to tell Nodejs the database operation is completed, so Nodejs executes the previously set callback function, The execution results of the database are processed. This is where nodejs is efficient, however, there are always two sides to everything, nodejs is efficient, but also increases the complexity of programmers writing programs, because the asynchronous program and the previous synchronization program is very different, let's take a look at a common considerations.

For loop + asynchronous operation

A classic problem is the callback function encountered in the loop:

var fs = require (' FS '); var files = [' A.txt ', ' b.txt ', ' c.txt '];  for (var i=0; i < files.length; i++) {    function(err, contents) {        + ': ' +
   
     contents);}    );
   

Assuming that the contents of these three files are: AAA, BBB, CCC, we expect the result is:

A.txt:aaab.txt:bbbc.txt:ccc

and the actual result is:

Undefined:AAAundefined:BBBundefined:CCC

What is this for? If we print the value of I in the loop, it can be seen that the data of three outputs is 3, which is the value of files.length. That is, the I value accessed in Fs.readfile's callback function is the value after the end of the loop, so the value of files[i] is undefined. There are a number of ways to solve this problem, which uses the JS function programming feature to create a closure to hold the I value required each time:

var fs = require (' FS '); var files = [' A.txt ', ' b.txt ', ' c.txt '];  for (var i=0; i < files.length; i++) {    (function(i) {        function (err, contents) {            + ': ' + contents);        })    (i);}

Because of the existence of a runtime closure, the variables defined in the anonymous function (including the parameter table) are not freed until the function inside it (the Fs.readfile callback function) is executed, so the i we access here is a different closure instance, created during the execution of the loop body, Different values are preserved. The closure is used here in order to see more clearly the reasons for the above output undefined, in fact, there can be a simpler way:

var fs = require (' FS '); var files = [' A.txt ', ' b.txt ', ' C.txt '];files.foreach (function(filename) {     function (err, contents) {        + ': ' + contents);    } );

More than one SQL query operation associated with

From the For loop above you can see clearly the difference between asynchronous programming and synchronous programming: Although efficient, there are many pits. Another example: if we need to do two SQL operations, but there is a clear need, the second must be completed after the first time, how to do? This is simple, just write the second operation inside the first callback function, because the first callback function triggers the premise that it has been executed. But what if the second operation requires the data returned by the first operation as a query condition, and to combine the two results to return it? Is it the following?

varSend_data =function(req,res) {SQL= ' SELECT gid,name,image_url,price,create_time,describes,selluid from goods WHERE status=? LIMIT?,? '; Connection.query (SQL, [0,0,6],function(Err, rows, fields) {if(ERR)Throwerr; Rows.foreach (function(item) {SQL= "Select Tag_name from Tag,tag_goods WHERE tag_goods.gid=?" and Tag_goods.tagid=tag.tagid "; Connection.query (SQL, Item.gid,function(Err, tags, fields) {if(ERR)Throwerr; Item.tags=tags;        });         }); Res.render (' Index ', {supplies:rows, login:req.session.login}); }};

The above example is to query the product information first, and then for each item, with its ID to query the list of tags, and add to each item information. Will the results returned above really be the same as expected? However, the Res.render () method has returned after only returning the product information that does not contain a label, that is, until the inner query execution is finished. Although we guarantee that the second query will be executed after the end of the first query, we cannot guarantee that the return statement returns after the end of the second query. There may be a number of specific solutions, here we use async module to solve the synchronization problem here.

Async function Introduction

Async mainly implements a number of useful functions, such as:

    • Each: If you want to perform the same asynchronous operation on all elements in the same collection.
    • Map: Performs an asynchronous operation on each element in the collection to get the result. All results will be aggregated into the final callback. The difference with each is that each only cares about the last value of the operation regardless of the last value, and the map cares about the final result.
    • Series: serial execution, each function in an array of functions, to execute the next function after each function is completed.
    • Parallel: Executes multiple functions in parallel, each function is executed immediately, without waiting for other functions to execute first. The data in the array passed to the final callback is in the order declared in the tasks, rather than in the order in which the completion is performed.
    • Other

Obviously, here we can use the map function to achieve our needs. The prototype of this method is: Map (arr, iterator (item, callback), callback (err, results)); In other words, we call the iterator () method with each element of ARR, the item iteration, and save each result, and when the iteration is over, bring the results together and call the callback () method to results. To apply this method, our program is modified to:

varAsync = require (' async ');varSend_data =function(req,res) {SQL= ' SELECT gid,name,image_url,price,create_time,describes,selluid from goods WHERE status=? LIMIT?,? '; Connection.query (SQL, [0,0,6],function(Err, rows, fields) {if(ERR)Throwerr; Async.map (Rows,function(item, callback) {SQL= "Select Tag_name from Tag,tag_goods WHERE tag_goods.gid=?" and Tag_goods.tagid=tag.tagid "; Connection.query (SQL, Item.gid,function(Err, tags, fields) {Item.tags=tags; Callback (NULL, item);        }); }, function(err,results) {Res.render (' Index ', {supplies:results, login:req.session.login});    }); }); };

At this point, the second SQL statement each query to the tag is saved to item, and so on after all the query ends, call callback (NULL, item), that is, all the data passed to the results parameter, and finally uniformly sent to the browser. In this case, the product tag tag is included.

1.node.js considerations when encountering "loop + Async"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.