I am using node js to develop my application. In controller i used a for loop and then wrote some code, but in for loop i am executing a query. So before that query completely executed once the code after for loop executing. See below for example.
var commcount = [];
for (var j = 0, len = exlist.length; j < len; j++) {
console.log('exlist[j].id '+exlist[j].id);
ExModel.find({EXModel_ID:exlist[j].id, VALUE: {'$ne':''}},{_id:0}, {sort: {CREATION_DATE: -1}}, function(err1, examplist) {
if (err1) {
console.log('sub error '+err1);
commcount.push(0);
} else {
console.log('examplist.length '+examplist.length);
commcount.push(examplist.length);
}
});
}
console.log('commcount length '+commcount.length);
In above code let us assume exlist.length is 5 so, for loop will be executed for 5 times. In the output console, First exlist[j].id value displaying all 5 times then commcount length value displaying as 0 then only examplist.length value diplaying. So before query executed the for loop for other statements and statements after for loop are being executed. Please help me to solve this. I want the length of result list of query in for loop to be stored in array and want to display those array values after for loop.
First of all you should know that you are calling asynchronous function, whatever the result you are getting is correct, The asynchronous function will run in separate thread, we can not guarantee the out put. Your code is similar to the below code, Let's run the below code
function run(){
console.log("d");
setTimeout(function(){
console.log("a");
setTimeout(function(){
console.log("b");
});
});
console.log("c");
}
The output will be d c a b.
Related
I have an array called noNCreatedResources. I want do some operation on each item of array and push item in createdResources array and remove the item from noNCreatedResources array and continue to do that until noNCreatedResources be empty. For this I've written CreateResources function including nested while and for loop. It works fine but i realize that it don't work synchronously. For example: it must iterate twice in while loop but iterates 4 times and I don't know why.
I think I don't understand concept of async/await/non-blocking concept of node.js. can any body help me to realize what the problem is?
CreateResources = async () => {
while (this.noNCreatedResources.length > 0) {
for (let index = 0; index < this.noNCreatedResources.length; index++) {
if (this.resourceHasCreatedDependencies(this.noNCreatedResources[index])) {
const resourceModel = this.someOperation(this.noNCreatedResources[index]);
this.createdResources.push(resourceModel);
this.noNCreatedResources.splice(index, 1);
}
}
}
}
First of all you are not doing anything asynchronous in you function so you can remove the async keyword from your function. Since you are not doing anything asynchronous so, your problem is not related to it. It is more of an implementation problem IMO.
Your while loop is useless for what you are trying to achieve. Also, your logic is broken!
Example: The following code will output 1, 3, and 5.
let x = [1,2,3,4,5];
for(let i = 0; i < x.length; i++) {
console.log(x[i]);
x.splice(i, 1);
}
I do not think you need to remove item from array to achieve your expected result. If you need to reset the array then at the end you can just do this x = [] to reset the array.
The problem you have is not due to async calls. Actually, your code is entirely synchronous. Try to take a look at where the "noNCreatedResources" is been created/updated. Async calls happens when you're sending a http request, reading a file etc, in other words, operations that doesn't happens inside your code. It allows the code to go on, not blocking the next function calls, and when the promise is fulfilled, the callback function is invoked.
i am new to node.js, i followed some tutorial.
I don't know how to get the array "result" only when the call in the function end.
app.get('/api/email/check/:email',function (request,response){
var email = request.params['email'];
var result = Array();
for (var i = 0; i < 2; i++) {
existence.check(email, function(err,res){
result[i]=res; console.log({"Result":res});
});
};
response.send(result); // Problem is that i get: []
});
I got the log but the result is an empty array because it's called before the functions ends. Is there a nice way to resolve this ? without counting the "i".
You can put
response.send(result);
out of the for loop.
Because response.send() is a async method so before the for loop ends, response has ended before.
Well the problem is simple, I am using a query within the for loop and and I want to get out of the for loop if I get the count less than 15, otherwise increase the assigned. But I can't be able to use the break statement and the loop will continue to execute even after the first callback.
for (var i = 0; i < test; i++) {
var sql = "SELECT count(*) as count FROM `tb_members` WHERE `assigned`=?";
connection.query(sql, [assigned], function (err, response) {
if (response[0].count < 15) {
callback(assigned);
}
else {
++assigned;
if (i == test - 1) {
callback(0);
}
}
});
}
The way your code is written, all your SQL queries are going to get started at once. Then, sometime later, the queries will start returning with results. So, you can't break out of the for loop because it's already done and all SQL queries have already been sent.
If you want to decide whether to send the next query based on the previous one's results, then you have to only send one at a time and because of the async nature of the results, you can't use a for loop for that.
One way of sending the queries one at a time and then deciding whether to send the next one is this:
function sendQueries() {
var i = 0;
function next() {
if (i < test) {
var sql = "SELECT count(*) as count FROM `tb_members` WHERE `assigned`=?";
connection.query(sql, [assigned], function (err, response) {
i++;
if (response[0].count < 15) {
callback(assigned);
} else {
++assigned;
if (i == test - 1) {
callback(0);
}
}
// here you can decide whether you want to do the next iteration
// or not by either calling next() or not.
next();
});
}
}
next();
}
You should be using async to write such a loop. If you want a serial behavior - you might consider using async.eachSeries, and then you can stop the loop by calling the callback function with error. At that point the loop will not execute anymore. But in the error handler - ignore the err.
Check it out here: https://github.com/caolan/async#collections
fabric.loadSVGFromURL when called in a loop always call the last callback, and not all the callbacks in the loop.
Looks like a closure issue in fabric loadSVGFromURL. The code below always print value 2 in console log which tells us that the callback is invoked only for the last iteration.
Code
var paths = ['walking-0.svg', 'walking-1.svg', 'walking-2.svg'];
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
fabric.loadSVGFromURL(path, (function (i) {
return function (objects, options) {
console.log(i); //always print 2, when the expected behaviour is to print all the three number starting from 0 to 2.
console.log(objects) //print only once, when it should print thrice
}
})(i));
}
Using Node.js and the node-postgres module to communicate with a database, I'm attempting to write a function that accepts an array of queries and callbacks and executes them all asynchronously using the same database connection. The function accepts a two-dimensional array and calling it looks like this:
perform_queries_async([
['SELECT COUNT(id) as count FROM ideas', function(result) {
console.log("FUNCTION 1");
}],
["INSERT INTO ideas (name) VALUES ('test')", function(result) {
console.log("FUNCTION 2");
}]
]);
And the function iterates over the array, creating a query for each sub-array, like so:
function perform_queries_async(queries) {
var client = new pg.Client(process.env.DATABASE_URL);
for(var i=0; i<queries.length; i++) {
var q = queries[i];
client.query(q[0], function(err, result) {
if(err) {
console.log(err);
} else {
q[1](result);
}
});
}
client.on('drain', function() {
console.log("drained");
client.end();
});
client.connect();
}
When I ran the above code, I expected to see output like this:
FUNCTION 1
FUNCTION 2
drained
However, the output bizarrely appears like so:
FUNCTION 2
drained
FUNCTION 2
Not only is the second function getting called for both requests, it also seems as though the drain code is getting called before the client's queue of queries is finished running...yet the second query still runs perfectly fine even though the client.end() code ostensibly killed the client once the event is called.
I've been tearing my hair out about this for hours. I tried hardcoding in my sample array (thus removing the for loop), and my code worked as expected, which leads me to believe that there is some problem with my loop that I'm not seeing.
Any ideas on why this might be happening would be greatly appreciated.
The simplest way to properly capture the value of the q variable in a closure in modern JavaScript is to use forEach:
queries.forEach(function(q) {
client.query(q[0], function(err, result) {
if(err) {
console.log(err);
} else {
q[1](result);
}
});
});
If you don't capture the value, your code reflects the last value that q had, as the callback function executed later, in the context of the containing function.
forEach, by using a callback function isolates and captures the value of q so it can be properly evaluated by the inner callback.
A victim of the famous Javascript closure/loop gotcha. See my (and other) answers here:
I am trying to open 10 websocket connections with nodejs, but somehow my loop doesnt work
Basically, at the time your callback is executed, q is set to the last element of the input array. The way around it is to dynamically generate the closure.
It will be good to execute this using async module . It will help you to reuse the code also . and will make the code more readable . I just love the auto function provided by async module
Ref: https://github.com/caolan/async