how to call function in node loop one at a time - node.js

this block of code process else block first and then if block, for all request at once, i need a code that execute 5 iterations stop for 15 sec. and then again continue from next 5 iterations and so on.
function passotken(token, callback) {
async.waterfall([
function(callback) {
db.executesql("select top 20 ext_id as EMPNUM , data as datae from newtable", function (data, err) {
callback(null, data);
});
},
function(data, callback) {
var _json_parse = JSON.parse(JSON.stringify(data));
var rows = data.length;
console.log(rows)
var cnt = 1;
for (var row = 1; row <= rows; row++) {
logger.info(_json_parse[row-1].EMPNUM);
//console.log(dateFormat(_json_parse[row].datae));
var req = 'https://pratik.com/ta/rest/v2/companies/|RHV/employees/|' +_json_parse[row-1].EMPNUM + '/timesheets?date=' + dateFormat(_json_parse[row-1].datae, "isoDate");
//console.log(req);
var myXMLText = req;
reques.push(myXMLText);
}
// console.log(reques);
for (var a = 0; a < rows; a++) {
//CURRENTLY PROCESSING ALL REQUEST IN IF BLOCK AND STOP FOR 15 SEC FOR ONLY FIRST IF CONDITION AFTER THAT ALL IF CONDITION PROCESSING WITHOUT HALT
if(a%5==0)
{
console.log("if");
//console.log(reques[a]);
//postreq(reques[a],token,sleeped(a));
/* setTimeout(function(){sleeped(reques[a],token);;
},15000); */
sleeped(reques[a],token);
//SHOULD PROCESS IF BLOCK ONCE AND STOP FOR 15 SEC
}
else
{
postreqELSE(reques[a],token);
//SHOULD PROCESS ALL REQUECT IN ELSE BLOCK TILL IF CONDITION ABOVE NOT SATISY
}
}
Promise.all(ps)
.then((results) => {
console.log("results"); // Result of all resolve as an array
}).catch(err => console.log("err"));
},
], function(err, result) {
if (!err)
console.log("Successfully completed")
else console.log(err);
});
};
function callback() {
console.log("completed successfully");
}
function postreq(request1,token)
{
//BLOCK
}
function sleeped(requesarr,token)
{
console.log("in sleeping");
//console.log(requesarr,token)
setTimeout(function(){
postreq(requesarr,token);
},15000);}
function postreqELSE(request2,token1)
{
console.log("in 3RD function");
//BLOCK2
}

Sure, this question was answered previously here: What is the JavaScript version of sleep()?
Following is an example which will do what you're requesting:
var reques = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function checkLoop()
{
for (var a = 0; a < 20; a++)
{ console.log("["+a+"] a%5 is: "+a%5);
console.log ( new Date().toLocaleTimeString());
if(a%5==0)
{ console.log("if");
console.log ( new Date().toLocaleTimeString());
await sleep(15000);
}
else
{ console.log("else");
console.log ( new Date().toLocaleTimeString());
}
}
}
checkLoop();
This prints out the following: (partial) Important to note that it will always pause on the first iteration because the index starts at 0, not 1.
[0] a%5 is: 0
8:58:38 AM
if
[1] a%5 is: 1
8:58:53 AM
else
8:58:53 AM
[2] a%5 is: 2
8:58:53 AM
else
8:58:53 AM
[3] a%5 is: 3
8:58:53 AM
else
8:58:53 AM
[4] a%5 is: 4
8:58:53 AM
else
8:58:53 AM
[5] a%5 is: 0
8:58:53 AM
if
8:58:53 AM
[6] a%5 is: 1
8:59:08 AM
else
8:59:08 AM
[7] a%5 is: 2
8:59:08 AM
else
8:59:08 AM
If you can't use async, then try this approach: (interval set at 1.5 secs for easier testing. just change the 1500 to 15000 to = 15 seconds)
var reques = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
var _interval;
var timeToWait = 1500;
function checkLoop(_init)
{
clearInterval(_interval);
console.log("checkLoop entered with value of: ", _init);
var start = (typeof(_init) == "undefined") ? 0 : _init;
console.log("start is: "+start);
for (var a = start; a < 20; a++)
{ console.log("["+a+"] a%5 is: "+a%5);
console.log ( new Date().toLocaleTimeString());
if(a%5==0)
{ console.log("if");
console.log ( new Date().toLocaleTimeString());
(function(_idx){_interval = setInterval(function(){checkLoop(_idx+1)}, timeToWait);})(a)
break;
}
else
{ console.log("else");
console.log ( new Date().toLocaleTimeString());
}
}
}
checkLoop();

Related

How to get code to execute in order in node.js

I am trying to finish my script, but for some reason i don't know, it refuses to execute in the order i put it in.
I've tried placing a 'wait' function between the JoinRequest update function and the following code, but when run, it acts as if the function call and wait function were the other way round, countering the point of the wait().
const Roblox = require('noblox.js')
var fs = require('fs');
var joinRequests = []
...
function wait(ms) {
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < ms*1000);
};
...
function updateJReqs() {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
});
}
function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
check();
} else {
updateJReqs(); //for some reason this function is executed alongside the below, not before it.
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
check();
}
});
}, 400)
}
check();
The script is supposed to wait until a file is created (accomplished), update the list of join requests (accomplished) and then create a new file with the list of join requests in(not accomplished).
if I understand your code you work with async code, you need to return a promise in updateJReqs and add a condition of leaving from the function because you have an infinite recursion
function updateJReqs() {
return new Promise(resolve => {
Roblox.getJoinRequests(4745601).then((array) => {
var i;
var final = [];
for(i = 0; i < array.length; i++) {
final.push(array[i].username);
};
if(final === '') {
final = '-None';
};
joinRequests = final
console.log('Updated join requests.')
resolve();
});
}
}
async function check() {
setTimeout(() => {
fs.readFile('Request.txt',encoding = 'utf-8', function(err, data) {
if (err) {
await check();
} else {
await updateJReqs();
// Tried putting wait(x) in here.
console.log('Request received: ' + data)
var solution = joinRequests
console.log('Fuffiling request with ' + solution)
fufillRequest(solution)
fs.unlink('Request.txt', function(err) {
if(err) throw err;
});
// you dont have an exit from your function check();
return 'Success';
}
});
}, 400)
}
check().then(res => console.log(res));

How to wait for google spreadsheet call and set it inside of a for loop

To get row from a google spreadsheet this code will work:
this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range,
}, (err, result) => {
if (err) {
// Handle error
console.log(err);
} else {
const numRows = result.values ? result.values.length : 0;
console.log(`${numRows} rows retrieved.`);
//Here I can use my rows
}
});
but how can I wait for this function to finish? Example:
console.log("1");
this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range,
}, (err, result) => {
if (err) {
// Handle error
console.log(err);
} else {
console.log("2");
}
});
console.log("3");
This will most likely print 132. Also is there a way to get the result and err outside of the current scope?
pseudo code from what I possible mean (should print 123):
console.log("1"); //Print 1
var getRows = this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range,
}
console.log("2"); //Print 2
if (getRows.err) {
// Handle error
console.log(getRows.err);
} else {
const numRows = getRows.result.values ? getRows.result.values.length : 0;
console.log(`${numRows} rows retrieved.`);
console.log("3") //Print 3
}
Edit:
I want the err outside of the scope so I can do somethng like this: (If the sheet call fails with code 429, the programm will sleep for 100sek and the try it again) pseudo code:
for(var i = 1; i < 5; i++){
var getRows = this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range,
}
console.log("2"); //Print 2
if (getRows.err) {
// Handle error
if(getRows.err.code === 429){
console.log("Too many requests, try again in 100sek");
await sleep(100000); //sleep function with 100sek
continue
}
//Some other code here
} else {
//logic for the results
console.log("3") //Print 3
}
console.log("Finished");
}
So 123 will be correctly printed and if the call fails it will be retried after 100sek with maximal 5 tries.
You can use promises instead of callbacks or async/await:
Snippet:
console.log("1");
var i = 0;
function loop(){
if( ++i > 5 ) return;
this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range,
})
.then(result => {
console.log(result);
console.log("2");
})
.then(()=>console.log("3"))
.catch(err=>{
console.log(err);
if(err.code === 429){
sleep(100000).then(loop)
}
})
}
References:
Promises
async
await
Nodejs client example
My Solution:
async function GetData() {
for (var i = 1; i <= 5; i++) {
try {
var data = await this.sheetsService.spreadsheets.values.get({
spreadsheetId,
range
});
return data;
} catch (err) {
if (err.code === 429) {
console.log("Too many requests, try again in 100sek");
await sleep(100000); //sleep function with 100sek
continue;
}
}
}
}

Getting output of mysql queries synchronously in node.js

I have the following code:
app.get('/showtable1', (req, res) => {
console.log("yo ho");
mysqlconnection.query('SELECT d_name FROM datacenters', (err, rows, fields) => {
if (!err) {
var array = [];
var tier = ['Class 0','Class 1','Class 2','Class 3'];
var str = '';
Object.keys(rows).forEach(function(key) {
var row = rows[key];
array.push(row.d_name);
});
for( var i = 0 ; i<array.length ; i++) {
str += '<tr><td>'+array[i]+'</td>';
console.log('sfsf');
for (var j=0 ; j< tier.length ; j++) {
let query1 = "SELECT * FROM `datacenters` WHERE d_name = '"+array[i]+"' AND d_tiers LIKE '%"+tier[j]+"%'"
mysqlconnection.query(query1,(err,rows) => {
if(!err) {
if(rows.length !=0) {
console.log(1);
} else {
console.log(0);
}
}
});
}
}
res.send(rows);
}
else
console.log(err);
})
});
The output of this code is:
yo ho
sfsf
sfsf
sfsf
1
1
0
0
1
1
1
0
1
1
1
0
But I need the output as:
yo ho
sfsf
1
1
0
0
sfsf
1
1
1
0
sfsf
1
1
1
0
The first output is coming because the code is running asynchronously; but I need to run it synchronously. How can I do this?
Asynchronous task does not have order. You can use Promise and async/await to get ordered output.
You can promisify your queries like:
function getNames() {
return new Promise((resolve, reject) => {
mysqlconnection.query('SELECT d_name FROM datacenters', (err, rows, fields) => {
if (!err) {
reject(err);
} else {
resolve(rows)
}
})
});
}
function getDatacenters(firstVal, tier) {
const query1 = "SELECT * FROM `datacenters` WHERE d_name = '"+firstVal+"' AND d_tiers LIKE '%"+tier+"%'";
return new Promise((resolve, reject) => {
mysqlconnection.query(query1,(err,rows) => {
if(!err) {
reject(err)
} else {
resolve(rows)
}
});
})
}
Then in your route
app.get('/showtable1', async (req, res) => {
console.log("yo ho");
const namesArray = [];
const names = await getNames();
Object.keys(names).forEach(function(key) {
var row = names[key];
namesArray.push(row.d_name);
});
const namesVal = [];
for (let i = 0; i < namesArray.length; i++) {
for (let j = 0; j < tier.length; j++) {
namesVal.push(getDatacenters(entry, tier));
}
}
// ordered array or result
const result = await Promise.all(namesVal)
...
// rest of the code
})
Note: I don't know which library you're using. Some libs provide Promise support so you don't have to write your own wrappers

For loop not working properly in node js

I want to insert multiple data by for loop , but this code add 2 or 3 data only , then its continue loading loading but nothing happen ...
router.post('/addclient' , function (req , res){
var finished = false;
var user = req.body.username;
for(var i = 0 ; i <30 ; i++){
req.body.username = user + i ;
objDB.insert("clientList" ,req.body, function(err, data){
//if(err) console.log(err);
if(i>20){
finished = true;
}
});
}
if(finished){
res.redirect('/client/client-list');
}
});
you are doing it wrong. insert is asynchronous, so when insert for i=1 completes and callback gets called, maybe i is equal to 20 and more and you can't guess it. you are missing synchronous and asynchronous concepts and differences.
here is two solutions for your problem :
first, adding 30 items at once :
var clientsList = [];
for (var i = 0 ; i < 30 ; i++) {
clientsList[i] = Ith client object; // create object you want to insert for client i
}
// for example insertAtOnce is a function to insert your list
objDB.insertAtOnce(clientsList,function(err,callback) {
if (err) console.log("error : ", err);
res.redirect('/client/client-list');
});
second, using bind
function insertCallback(itr, res, err,callback) {
if (itr == 29) {
res.redirect('/client/client-list');
}
}
----
for(var i = 0 ; i <30 ; i++){
req.body.username = user + i ;
objDB.insert("clientList" ,req.body,insertCallback.bind(null, i, res);
}
Would be best if you use the async node.js library which provides control flows like running each function in series. You could use the async.whilst() method and restructure your code as:
router.post('/addclient', function(req, res) {
var user = req.body.username,
count = 0,
result = { finished = false };
async.whilst(
function () { return count < 30; },
function (callback) {
count++;
req.body.username = user + count.toString();
objDB.insert("clientList", req.body, function(err, data){
if (err) { return callback(err); }
result["data"] = data;
if( count > 20 ) result.finished = true;
callback(null, result);
});
},
function (err, result) {
if (err) { /* handle err */};
if (result.finished) res.redirect('/client/client-list');
}
);
});
You have a callback called after running insert function. It runs not exactly after running insert, and not in loop(it asynchronous). So in your code res.redirrect will never be called, because finished will be true after all loop will run. If you don't need to have all this inserts finished before answer, you can go this way:
if(i == 29){
res.redirect('/client/client-list');
}
Otherwise you need to create some queue, for example, i'm using async library https://github.com/caolan/async to create queues and running callbacks after queue ends.
router.post('/addclient', function(req, res) {
var finished = false;
var user = req.body.username;
var i = 0;
while( true ) {
if ( i > 20 ) {
res.redirect('/client/client-list');
}
req.body.username = user + i;
var promise = new Promise();
objDB.insert("clientList", req.body, function(err, data) {
promise.resolve();
});
promise.then(function() {
i++;
continue;
});
}
});
I have written it from the top of my head. But the basic idea here is that you need a loop to run infinitely, then resolve a promise; the resolution triggers continuing the loop, and increment the counter.
Use Promise. I would have done something like below
router.post('/addclient' , function (req , res){
var finished = false;
var promise = [];
var user = req.body.username;
for(var i = 0 ; i <30 ; i++) {
req.body.username = user + i;
promise.push(new Promise(resolve, reject) {
objDB.insert("clientList" ,req.body, function(err, data) {
if(err) {
reject(err)
return
}
resolve(data)
})
})
}
Promise.all(promise).then(function() {
finished = true
})
if(finished){
res.redirect('/client/client-list');
}
});

Loop synchronous multiple async.whilst

I want to use many included loops in node.js in synchronous mode.
Example :
for (var i = 0; i < length1; i++) {
for (var j = 0; j < length2; j++) {
for (var k = 0; k < length3; k++) {
//completed 3
}
//completed 2
}
//do completed 1
}
How to do this with async? I tried this :
exports.myFunction = function (callback) {
var finalListA = new Array();
var pos = 0;
Model_A.find().populate('listOfItems')
.lean().exec(function (err, As) {
if (err) {
console.log(err);
return callback(err, null);
} else {
//For each A
var i = 0;
async.whilst(
function () {
return i < As.length;
},
function (callback1) {
var isActive = false;
//For each B into the A
var j = 0;
async.whilst(
function () {
return j < As[i].Bs.length;
},
function (callback2) {
Model_B.findById(AS[i].Bs[j]._id, function (err, B) {
if (err) {} else {
var k = 0;
// For each C in the B
async.whilst(
function () {
return k < B.Cs.length;
},
function (callback3) {
if (B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
}
k++;
callback3();
},
function (err) {
console.log("3 COMPLETED");
}
);
}
});
j++;
callback2();
},
function (err) {
console.log("2 COMPLETED");
if (err) {} else {
if (isActive == true) {
finalListA[pos] = As[i];
pos = pos + 1;
}
}
}
);
i++;
callback1();
},
function (err) {
console.log("1 COMPLETED");
if (err) {} else {
return callback(null, finalListA);
}
}
);
}
});
}
The trace shows me :
COMPLETED 2
COMPLETED 2
COMPLETED 1
COMPLETED 3
COMPLETED 3
The order expected is :
COMPLETED 3
COMPLETED 3
COMPLETED 2
COMPLETED 2
COMPLETED 1
You must call the callbacks of the higher loops from the end callback of your whilst loop (like you did with the outermost callback), instead of calling them synchronously from the whilst body in which you just started the next level iteration.
Btw, I don't know what you actually want to do, but whilst does not seem the best choice for iterating arrays. Use the parallel each or the serial eachSeries (or their map or reduce equivalents).
I've recently created simpler abstraction called wait.for to call async functions in sync mode (based on Fibers). It's at an early stage but works. It is at:
https://github.com/luciotato/waitfor
Using wait.for, you can call any standard nodejs async function, as if it were a sync function.
I do not understand exactly what are you trying to do in your code. Maybe you can explain your code a little more, or give some data example.
I dont' know what Model_A or Model_B are... I'm guessing most of your code, but...
using wait.for your code migth be:
var wait=require('wait.for');
exports.myFunction = function(callback) {
//launchs a Fiber
wait.launchFiber(inAFiber,callback);
}
function inAFiber(callback) {
var finalListA = new Array();
var pos = 0;
var x= Model_A.find().populate('listOfItems').lean();
As = wait.forMethod(x,"exec");
//For each A
for(var i=0;i<As.length;i++){
var isActive = false;
//For each B into the A
for(var j=0; j < As[i].Bs.length;j++){
var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
// For each C in the B
for(var k=0; k < B.Cs.length;k++){
if(B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
}
}
console.log("3 COMPLETED");
}
console.log("2 COMPLETED");
if(isActive == true) {
finalListA[pos] = As[i];
pos = pos + 1;
}
};
console.log("1 COMPLETED");
return callback(null,finalListA);
}
Also, for what I see, you should break the loops as soon as you find one item (isActive), and you don't need the var pos. Doing that your code will be:
var wait=require('wait.for');
exports.myFunction = function(callback) {
//launchs a Fiber
wait.launchFiber(inAFiber,callback);
}
function inAFiber(callback) {
var finalListA = [];
var x= Model_A.find().populate('listOfItems').lean();
As = wait.forMethod(x,"exec");
var isActive;
//For each A
for(var i=0;i<As.length;i++){
isActive = false;
//For each B into the A
for(var j=0; j < As[i].Bs.length;j++){
var B=wait.forMethod(Model_B,"findById",AS[i].Bs[j]._id);
// For each C in the B
for(var k=0; k < B.Cs.length;k++){
if(B.Cs[k].dateEnd >= Date.now()) {
isActive = true;
break;//for each C
}
} //loop for each C
console.log("3 COMPLETED");
if (isActive) break;//for each B
} //loop for each B
if (isActive) finalListA.push(As[i]);
console.log("2 COMPLETED");
} //loop for each A
console.log("1 COMPLETED");
return callback(null,finalListA);
}

Resources