turning a synchronous function into asynchronous function - node.js

I have a for loop which does many iterations .I would like to put that piece of code in a custom async function as it is blocking.Is there anyway I can write a function so it will call a callback once the loop iteration is over?.

Use asynchronous-function-inside-a-loop paradigm. This ensures that the asynchronous functions get called with the correct value of the index variable.
var total = someObject.list.length;
var count = 0;
for(var i = 0; i < total; i++){
(function(foo){
myobj.get(someObject.list[foo], function(err, response) {
do_something(foo);
count++;
if (count > total - 1) done();
});
}(i)); //To immediately invoke the function passing 'i' as parameter
}
function done() {
console.log('All data loaded');
}

Related

How to Create a function in Node.js

I am using Firebase function to create an API and at the same time I Am using the Firebase Firestore as my database.
I am using Node.js to create the program.
I wanted to know how to create a function in Node.js.
I will be calling a code more than once and since I have been use to Java and Java has molecularity will it be possible in Node.js also?
This is my code
exports.new_user = functions.https.onRequest((req, res) => {
var abc=``;
if(a=='true')
{
abc=Function_A();//Get the results of Function A
}
else
{
abc=Function_B();//Get the results of Function B
//Then Call Function A
}
});
As shown in the code I would be calling the same function two times from different location depending upon the situation and then utilizing the result of it.
Is it possible to declare a function and then call if from different locations and then utilize its result?
Any help would be really appreciated as I am new to Node.js
If you are trying to just get a value back from the function it depends if you are doing synchronous (adding 2 numbers together) or asynchronous (doing an HTTP call)
synchronous:
let abc = 0;
if(a=='true')
{
abc = Function_A();//Get the results of Function A
}
else
{
abc = Function_B();//Get the results of Function B
//Then Call Function A
}
function Function_B() {
return 2+2;
}
function Function_A() {
return 1+1;
}
asynchronous:
let abc = 0;
if(a=='true')
{
Function_A(function(result) {
abc = result;
});//Get the results of Function A
}
else
{
Function_A(function(result) {
abc = result;
});//Get the results of Function A
}
function Function_B(callback) {
callback(2+2);
}
function Function_A(callback) {
callback(1+1);
}
Asynchronous with variable:
let abc = 0;
Function_A(2, function(result) {
abc = result; //should by 4
});//Get the results of Function A
function Function_A(myVar, callback) {
callback(myVar * 2);
}

Need to execute function when forEach functions ends

I have this code in node js / firebase :
ref.child("recipts").once("value", function(usersSnap) {
usersSnap.forEach(function(reciptsSnap) {
reciptsSnap.forEach(function(reciptSnap) {
reciptSnap.ref.child("last_recipt").once("value", function(b) {
b.forEach(function(c) { //Here I fill some "product" object
});
});
reciptSnap.forEach(function(b) { //Here I fill some "product" object
});
});
});
});
I need to execute a function just when "reciptSnap" forEachs finished. How can I accomplish this, I try using a variable i++ and i-- but only work for one forEach iteration.
The function I call is for manipulating the product object I created with the filled data from the forEachs loops.
If I have understood correctly, you want to call a function when reciptsSnap.forEach is complete and all async tasks inside it are also complete.
For achieving this, you can use the index parameter and the original array that is passed to the callback function of forEach. (See Documentation)
The code will be like this:
(Note: The following code is without changing the current forEach loop structure used. However, re-writing the code with Promise or async would be a better & cleaner way to do it).
var loop1Done = false;
var loop2Done = false;
ref.child("recipts").once("value", function (usersSnap) {
usersSnap.forEach(function (reciptsSnap) {
reciptsSnap.forEach(function (reciptSnap, index, colA) {
const idx = index;
const col = colA;
reciptSnap.ref.child("last_recipt").once("value", function (b) {
const i = idx;
const c = col;
b.forEach(function (c, j, colB) { //Here I fill some "product" object
// Do what you want here
// Check if all done for this loop
if ((j >= colB.length) && (i >= c.length)) {
loop1Done = true;
// Check if all loops done
if (loop1Done && loop2Done) {
// Call final callback function
// e.g. myFinalCallback();
}
}
});
});
reciptSnap.forEach(function (b, k, colC) { //Here I fill some "product" object
const i = idx;
const c = col;
// Do what you want here
// Check if all done for this loop
if ((k >= colC.length) && (i >= c.length)) {
loop2Done = true;
// Check if all loops done
if (loop1Done && loop2Done) {
// Call final callback function
// e.g. myFinalCallback();
}
}
});
});
});
});
Try:
reciptSnap.child("last_recipt").forEach(function(b) {
b.forEach(function(c) {
//Here I fill some "product" object
});
});
This should work since all of your data should already have been fetched when you did "value" on the receipts node.
If this works, your code is no longer asynchronous and right after the last forEach, you can execute the function you wanted to.
reciptSnap.forEach(function(b) {
//Here I fill some "product" object
});
//Execute your function here
});

Passing variable from function to outside the function

I'm trying to get a variable (listID) passed from the function to outside the function and I'm getting the result as undefined. I see this requires a callback, but I'm not clear on how to do this (I'm new to nodejs).
Can anybody show me how this would be done? Thanks.
twitter.get('/lists/list', function(err, data, response) {
for (var i = 0; i < data.length; i++) {
var j=i+1;
if (j==number){
var listID=data[i].id;
}
}
});
console.log(listID);

Getting undefined because of asynchronous calling

I'm having a bit of a problem here. I'm working on a backend on NodeJS for a Sencha Touch app and at some point I'm calling a function, but I'm getting to next line of code before getting that functions return statement.
Here's my code...
.... for loop ....
if(resultSet[k].id_bus == busDocs[n].id_bus && resultSet[k].id_bus_variation == busDocs[n].id_bus_variation){
resultSet[k].s_origin_description = busDocs[n].s_origin_description;
resultSet[k].s_eta = vehicle != null ? getVehicleETA(db, vehicle) : 'Unknown';
console.log('after getting eta');
resultSet[k].s_destination_description = busDocs[n].s_destination_description;
}
}
}
res.send(JSON.stringify(resultSet));
....
and this is my getVehicleETA function...
getVehicleETA = function(db, vehicle){
var position = vehicle.position;
function compare(a,b) {
if (a.n_stop_number < b.n_stop_number)
return -1;
if (a.n_stop_number > b.n_stop_number)
return 1;
return 0;
}
db.get('busstops').find({$query:{$and:[{id_bus: vehicle.id_bus}, {id_bus_variation: vehicle.id_bus_variation}]},$orderBy:{n_stop_number: 1}},function(e, docs){
var distance = 0;
if(docs.length != 0){
docs.sort(compare);
var nextBusStop = null;
for(var i=0; i<docs.length; i++){
if(i+1 < docs.length){
var routeSegmentLength = Math.sqrt(Math.pow(docs[i +1].coord_x - docs[i].coord_x, 2) + Math.pow(docs[i +1].coord_y - docs[i].coord_y, 2));
var firstStopDistance = Math.sqrt(Math.pow(vehicle.coord_x - docs[i].coord_x, 2) + Math.pow(vehicle.coord_y - docs[i].coord_y, 2));
var secondStopDistance = Math.sqrt(Math.pow(vehicle.coord_x - docs[i +1].coord_x, 2) + Math.pow(vehicle.coord_y - docs[i +1].coord_y, 2));
if(nextBusStop != null){
distance += routeSegmentLength;
}
if(secondStopDistance < routeSegmentLength && firstStopDistance < routeSegmentLength){
nextBusStop = docs[i+1];
}
}
}
console.log(((distance/(1000 * vehicle.speed)) * 60))
return ((distance/(1000 * vehicle.speed)) * 60);
}
});
}
If this was working correctly I would have to see getVehicleETA's console.log first, and then console.log('after getting eta'); but I'm getting it the other way around. I know this is actually correct behaviour as it didn't block the thread and kept going on in the code, but this is not working for me, because I'm sending the resultSet before even getting my getVehicleETA result, and I need resultSet's items to have it's s_eta property set before sending them.
What's the correct way of doing this?
Correct way is to have a callback in getVehicleETA function.
Let me show you as an illustration:
getVehicleETA = function(db,vehicle,callback){
/*do some stuff*/
//return the result in callback.
callback(result);
}
resultSet[k].s_origin_description = busDocs[n].s_origin_description;
if(vehicle!=null){
getVehicleETA(db,vehicle,function(result){
resultSet[k].s_eta = result;
nextAction()
});
}else{
resultSet[k].s_eta = "unknown";
nextAction();
}
function nextAction (){
console.log('after getting eta');
resultSet[k].s_destination_description = busDocs[n].s_destination_de
res.send(JSON.stringify(resultSet));
}
Hope this works for you.
You're calling an asynchronous function as if it were synchronous. Also, returning a value from a callback for an asynchronous function is meaningless. You have to pass in a callback to the function and then call that callback within your database callback with the values from the database.
You should look into using the async module to help you handle asynchronous function calls in a loop.

Phased execution recursive cycle in Node.js

I'm new to Node.js and asynchronous programming in general, and I have a problem. I need for continuous work server in a recursive loop, which steps would be implemented consistently, and each stage should consist of an asynchronous receive data over websotskets (this is already has understood), or go to next stage on the expiration of timer.
I am aware that is it not a trivial task, but how to implement it, what libraries can help?
I tried to understand the Step.js and Node.js events, this is what i need?
If I wrote all this in sync:
//CODE FOR STACKOVERFLOW
var previous_round = 'qwerty';// this is string, selected in previous cycle
var round_users = users;// 'users' is array of soceket.id all connected users and here a put them into new array 'round_users' with sockets for current cycle
io.sockets.emit('users_round', { number: round_users.length }); // send to users information about number of users in new round
for (var i = 0; i < round_users.length; i++) {
io.sockets.socket(round_users[i]).emit('round', { text: previous_round });//for each socket in 'round_users' emit event to enter chat message
} // and send selected in previous round message
var messages = []; // array of users messages
//now we must listen users events and start timer for next stage
//listen users events
for (var i = 0; i < round_users.length; i++) {
io.sockets.socket(round_users[i]).on('message', function (data) {
messages[messages.length] = data.text;//write text from users to array
if (messages.length == round_users.length) { /* GO TO NEXT STAGE */ } // it's after previous operation in this function
});
}
//or set timeout
setTimeout(/* GO TO NEXT STAGE */,15000);
for (var i = 0; i < round_users.length; i++) {
io.sockets.socket(round_users[i]).emit('voting', { messages_array: messages });//for each socket in 'round_users' emit event to vote perfect chat message
} // and send messages, which they send to server
//i'm not quite sure about this decision of vote counting :-)
var votes = []; //array with users votes
for (var i = 0; i < messages.length; i++) {
votes[i] = 0;
}
//now we must listen users events and start timer
//listen users events
for (var i = 0; i < round_users.length; i++) {
io.sockets.socket(round_users[i]).on('vote', function (data) {
votes[data.number]++;//increment selected message
if (votes.length == messages.length) { /* GO TO NEXT STAGE */ } // it's after previous operation in this function
});
}
//or set timeout
setTimeout(/* GO TO NEXT STAGE */,10000);
var max_id = 0; //now select max number from 'votes' array
for (var i = 0; i < votes.length; i++) {
if (votes[i]>votes[max_id]) {max_id = i;} //yet without the same values
}
var previous_round = messages[max_id]; //set up string value of selected message
//restart cycle
this code on pastebin with syntax highlighting
Recursion in the most basic sense is just a function that calls itself over and again, but in this instance with node you may want to utilize process.nextTick() to allow other events to occur during this recursion.
Here is a simple example of one way you might be able to go about it:
function someFunction(args, callback) {
// Check requirements
if (typeof callback !== 'function') return console.log('Callback required');
if (typeof args === 'undefined') return callback('Arguments required');
// Set defaults
var err = false;
var result = false;
// Do other stuff
anotherFunctionWithAcallback(args, function(err, result) {
if (err) return callback(err);
// This way, the nextTick only occurs after processing completes
return callback(err, result);
}
}
(function loop(stage) {
// When the stage argument is not provided, default to stage 1
stage = (typeof stage === 'undefined') ? 1 : stage;
switch(stage) {
case 1:
/* stage 1 */
someFunction(args, function(err, result){
process.nextTick(loop(2));
});
break;
case 2:
/* stage 2 */
someFunction(args, function(err, result){
process.nextTick(loop(3));
});
break;
case 3:
/* stage 3 */
someFunction(args, function(err, result){
// No stage argument, restart at stage 1 by default
process.nextTick(loop());
});
break;
}
})(); // Execute this function immediately

Resources