johnnash
johnnash

Reputation: 424

Handle queries inside loop in node.js

In the following code, the val variable value keeps changing due to asynchronous behavior and generates unexpected output i.e. before connection query for first loop is finished, var variable according to second loop and generates wrong output.What is the best way to handle queries in loop that avoid idiosyncrasies caused by asynchronous nature.

    var output = [];
    for ( var j = 0; j < someArr.length ; j++ ) {
         val = someArr[j];//some manipulation of someArr[j]
         connection.query( "select id from someTable where someCol = ?",val, function(err, rows, fields) {
             if ( err ) {
               console.log( err );
             } else {
               output.push( rows[0].someVal );//push query output to this variable
             }
       });
    }

console.log( output );//should contain output for all queries.

Upvotes: 3

Views: 11015

Answers (3)

SharpEdge
SharpEdge

Reputation: 1762

Just use a closure to generate a temporary scope

var output;
    for ( var j = 0; j < someArr.length ; j++ ) {
         tVal = someArr[j];//some manipulation of someArr[j]
         (function(val){
           connection.query( "select id from someTable where someCol = ?",val, function(err, rows, fields) {
               if ( err ) {
                 console.log( err );
               } else {
                 output.push( rows[0].someVal );//push query output to this variable
               }
           });
         })(tVal);
    }

Theory

Execution Context

JavaScript is a single threaded language, meaning only one task can be executed at a time. When the JavaScript interpreter initially executes code, it first enters into a global execution context by default. Each invocation of a function from this point on will result in the creation of a new execution context.

The Scope Chain

For each execution context there is a scope chain coupled with it. The scope chain contains the variable object for every execution context in the execution stack. It is used for determining variable access and identifier resolution.

Explanation

The anonymous function help us to create a new scope "blocking" the value of tVal because when is executed a new scope is added to the scope chain containing val value. This new scope is a child of the parent scope in wich the for loop is executed, when the cycle continues tVal change but val is contained in the child scope and is safe from the variation.

Upvotes: 5

Srinath
Srinath

Reputation: 295

Try "let" instead of "var" This might work

var output = [];
    for ( let j = 0; j < someArr.length ; j++ ) {
         val = someArr[j];//some manipulation of someArr[j]
         connection.query( "select id from someTable where someCol = ?",val, function(err, rows, fields) {
             if ( err ) {
               console.log( err );
             } else {
               output.push( rows[0].someVal );//push query output to this variable
             }
       });
    }

Upvotes: 3

Bhaurao Birajdar
Bhaurao Birajdar

Reputation: 1507

The best & standard way to use loop & inside the that execute query is use async.eachSeries.

So using async.eachSeries it will execute one by one in series & once foreach complete you can use callback.

Ref : http://caolan.github.io/async/docs.html#eachSeries

var async = require('async');
var output = [];
connection.query('SELECT * FROM tablename LIMIT 10',function(error,results,filelds){
    if(error) throw err;

    async.eachSeries(results,function(data,callback){ // It will be executed one by one
            //Here it will be wait query execute. It will work like synchronous
            connection.query('SELECT * FROM tablename  where id = 1',function(error,results1,filelds){
                if(error) throw err;

                output.push(results1[0].id)
                callback();
            });

    }, function(err, results) {
        console.log(output); // Output will the value that you have inserted in array, once for loop completed ex . 1,2,3,4,5,6,7,8,9
    });


})

Upvotes: 3

Related Questions