How to use setTimeout in Node.JS within a synchronous loop? - javascript

The goal I'm trying to achieve is a client that constantly sends out data in timed intervals. I need it to run indefinitely. Basically a simulator/test type client.
I'm having issues with setTimeout since it is an asynchronous function that is called within a synchronous loop. So the result is that all the entries from the data.json file are outputted at the same time.
But what i'm looking for is:
output data
wait 10s
output data
wait 10s
...
app.js:
var async = require('async');
var jsonfile = require('./data.json');
function sendDataAndWait (data) {
setTimeout(function() {
console.log(data);
//other code
}, 10000);
}
// I want this to run indefinitely, hence the async.whilst
async.whilst(
function () { return true; },
function (callback) {
async.eachSeries(jsonfile.data, function (item, callback) {
sendDataAndWait(item);
callback();
}), function(err) {};
setTimeout(callback, 30000);
},
function(err) {console.log('execution finished');}
);

You should pass the callback function:
function sendDataAndWait (data, callback) {
setTimeout(function() {
console.log(data);
callback();
//other code
}, 10000);
}
// I want this to run indefinitely, hence the async.whilst
async.whilst(
function () { return true; },
function (callback) {
async.eachSeries(jsonfile.data, function (item, callback) {
sendDataAndWait(item, callback);
}), function(err) {};
// setTimeout(callback, 30000);
},
function(err) {console.log('execution finished');}
);

Related

Callbacks Exercise Javascript

I have been exercising callbacks and I got this exercise that I have been struggling with the syntax. Here is my code:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
doLaundry([wash, dry, fold]);
Invoking the doLaundry([wash,dry,fold]) is supposed to print out the following:
wash dry fold Done!
by calling this function (needs work)
function doLaundry() {
// Call functions
}
I tried this and it was close but the syntax is wrong or uneeded:
function doLaundry(actions, callback) {
actions.forEach((item, index) => {
wash(item, (error) => dry(item, (error) => fold(item, (error) => {})));
});
}
I'm really confused how to implement the doLaundry() with callback after checking out other simple tutorials. Any suggestions how to approach this?
Since the functions don't need to be asynchronous, I think you're making this a lot more complicated than it needs to be. Just iterate through the array of actions (functions) and call them. Then log Done at the end.
function wash() {
console.log('wash');
}
function dry() {
console.log('dry');
}
function fold() {
console.log('fold');
}
const doLaundry = (fns) => {
fns.forEach(fn => {
fn();
});
console.log('Done!');
}
doLaundry([wash, dry, fold]);
Or, if you must stick with the asynchronous functions, you can build up the callback chain starting from the last one in the chain and going backwards with reduceRight:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
const doLaundry = (fns) => {
const firstCallback = () => console.log('done');
const firstFn = fns.reduceRight(
(nextCallback, fn) => () => fn(nextCallback),
firstCallback
);
firstFn();
}
doLaundry([wash, dry, fold]);
Or, for an easier to understand approach, promisify each callback and await them:
function wash(callback) {
setTimeout(function() {
console.log('wash');
callback();
}, 3000);
}
function dry(callback) {
setTimeout(function() {
console.log('dry');
callback();
}, 2000);
}
function fold(callback) {
setTimeout(function() {
console.log('fold');
callback();
}, 1000);
}
const toProm = fn => new Promise(resolve => fn(resolve));
const doLaundry = async (fns) => {
for (const fn of fns) {
await toProm(fn);
}
console.log('done');
}
doLaundry([wash, dry, fold]);
Try this simple code:
only one thing that you have to remember is, in the callback function if we are passed arguments, you have to write something in front of the callback like this
()=>
function wash(dry) {
console.log("wash");
setTimeout(dry, 3000);
}
function dry(fold) {
console.log("dry");
setTimeout(fold, 2000);
}
function fold(done) {
console.log("fold");
console.log("done");
}
setTimeout(() => wash(() => dry(() => fold("done"))), 4000);
function wash(callback){
setTimeout(()=>{
console.log('wash');
callback()
},3000)
}
function dry(callback){
setTimeout(()=>{
console.log('dry');
callback()
},2000)
}
function fold(callback){
setTimeout(()=>{
console.log('fold');
callback()
},1000)
}
function doLaundry(callback){
callback()
}
doLaundry(()=>{
wash(()=>{
dry(()=>{
fold(()=>{
console.log('done')
})
})
})
});
This one should do the job.
function doLaundry(actions) {
const [_wash, _dry, _fold] = actions
_wash(() => {
_dry(() => {
_fold(() => {
console.log('Done')
})
})
})
}
First line is destructuring the array, so it's elements are easier to access:
const [_wash, _dry, _fold] = actions
Function doLaundry takes array of callback functions as argument, which means when calling those functions inside of body of doLaundry, only names which it takes from arguments should be provided together with arguments that those callback functions are taking.
Since all of them take callbacks as arguments, arguments must be another function. First callback function's (in this case _wash) argument is another callback (_dry), therefore it takes another function as argument. If _wash's argument wasn't another function that takes callback as argument, it would be done like this:
_wash(_dry)
Last callback (_fold) also takes a callback as an argument which is in this case an anonymous function.

Wait for inner functions to wait and execute then proceed execution

I am executing a cloud function which is written in nodeJS.Here the function triggers when a data from the external source comes in and in this function, I have to call and check DB at the particular table but it takes more than 5 seconds and before the execution of my getDataFromDb function my main function completed execution. Plus there is a function called updateItems(postdate); and it executes if I cannot find data in my DB when triggering getDataFromDb
I tried async await but I am not sure where I am doing wrong. my function always ends first before my DB operation ends.
exports.handler = (event, context) => {
//here i am making data ready for DB and checking for the record if that is present in db
getDataFromDb(uniqueArray);
function getDataFromDb(uniqueArray) {
var params = {
// params for get reques
}
//db get operation
db.get(params, function (err, data) {
//takes time here
if (err) {
console.log(err); // an error occurred
}
else {
//another DB operation updateItems(postdata);
//takes time here
}
else {
console.log("first run for db")
//another DB operation updateItems(postdata);
//takes time here
}
}
});
}
});
console.log("main function ended")
};
the expected result should wait for the inner function to execute then end the main function but actually, the main function ends first then DB calling function ends
Though this can be achieved through callbacks, converting it to promise chain makes it easy, as execution of inner function depends on outer function, it's better to chain promises i.e. return Promise in the call back of first function, to execute them serially.
exports.handler = (event, context) => {
getDataFromDb(uniqueArray).then(success => {
console.log('Done')
})
.catch(err => {
console.log('handle get or post err here');
});
function getDataFromDb(uniqueArray) {
var params = {};
return new Promise((resolve, reject) => {
db.get(params, (err, data) => {
if (err) {
return reject(err); // an error occurred
} else {
return resolve(data);
}
});
}).then(success => updateItems(data))
}
});

Proper way to use setInterval on multiple HTTP requests with Node

Say you have a list which contains 3 ~ 5 urls. Requests should be made every 5 seconds, one by one. I wrote code like :
setInterval(() => {
array.foreach(element => {
request
.get(element.url)
.on('response', function(response) {
console.log(response);
}
});
}, 5000)
But because the enqueueing setInterval is faster than executing the request, the .on callback is not responding. I think, before enqueueing setInterval, I must ensure that the I've finished .on callback.
How can I do that?
Recommend you the Async.js module.
If you want a async loop to solve, you can:
var i = 0;
async.whilst(
function() { return i < array.length; },
function(next) {
var elemet = array[i++];
request
.get(element.url)
.on('response', function(response) {
console.log(response);
// Do next while 5s passed
setTimeout(next, 5000);
}
}
},
function (err, n) {
// All Task over
}
);
Or if you want try some concurrency:
// create a queue object with concurrency 2
var q = async.queue(function(task, next) {
console.log('request ' + task.url);
request
.get(task.url)
.on('response', function(response) {
console.log(response);
next();
}
}
}, 2);
// assign a callback
q.drain = function() {
console.log('all task have been processed');
};
// Push a request task to the queue every 5s
setInterval(function () {
let task = array.shift()
if (task) {
q.push(task, function(err) {
console.log('finished processing', task.url);
});
}
}, 5000);
Can you please try this?
var requestArray = [
{
url: 'some URL number 1'
},
{
url: 'some URL number 2'
},
{
url: 'some URL number 2'
}
]
function makeRequests(){
for(var i=0; i<requestArray.length; i++){
request.get(requestArray[i].url)
.on('response',function(response){
console.log(response);
if(i == requestArray.length - 1)//You can check any condition here if you want to stop executing get requests{
makeRequests();
}
})
}
}

nodejs async each function

In node js, i am using async function to get the result from another function and store it as array and return the result. But here i am getting empty json as output {}. See the comments inside code block. May i know where i am doing mistake ?
collectSearchResult: function (searchConfig, callback) {
var searchResult = {};
async.each(searchConfig.scope, function (scope, callback) {
var query = {
"query": {
"match": {
"_all": searchConfig.q
}
},
operationPath = scope.url;
this.doSearch(operationPath, query, function (err, results) {
var type = scope.type;
searchResult[type] = results;
// Here i am able to get correct output async
console.log(searchResult);
});
callback();
}.bind(this), function (err) {
// Here it is just returning empty json like {}. this function is called before this.doSearch complete its task
console.log(searchResult);
callback(err, searchResult);
});
}
collectSearchResult: function (searchConfig, callback) {
var searchResult = {};
async.each(searchConfig.scope, function (scope, callback) {
var query = {
"query": {
"match": {
"_all": searchConfig.q
}
},
operationPath = scope.url;
this.doSearch(operationPath, query, function (err, results) {
var type = scope.type;
searchResult[type] = results;
// Here i am able to get correct output async
console.log(searchResult);
//<><><><><><><>
callback(); //you need to place the callback for asynch.each
//within the callback chain of your query, else async.each
//immediately finishes before your data has arrived.
//<><><><><><><>
});
}.bind(this), function (err) {
// Here it is just returning empty json like {}. this function is called before this.doSearch complete its task
console.log(searchResult);
callback(err, searchResult);
});
}

How does nesting async functions inside the final callback work?

var foo = function (callback_foo) {
async.series([func1, func2, func3], function (err) {
if (err) {
return callback_foo(err)
}
async.series([func4, func5], function(err){
if (err) {
return callback_foo(err)
}
return callback_foo(); //1
});
return callback_foo(); //2
});
}
do I need to return callback_foo() two times? the first callback_foo() is to tell async.series func4, fun5 is done. And the second callback_foo() is to tell the outer async.series func1,func2, func3 are done. is that right?
you could do it like below.
var foo = function (callback_foo) {
async.series([
func1(callback) {
//func1 processing
callback(); //this will call func2 after func1 is done
},
func2(callback) {
//func2 processing
callback(); //this will call func 3 after func 2 is done
},
func3(callback) {
//do your func3 processing here,then call async.series for 4 and 5.
async.series([
func4(callback) {
//do func 4 processing here
callback(); //This will call func5 after func4 is done
},
func5(callback) {
//do func5 processing here
callback(); //this will call the final callback of the nested async.series()
}], function (err) {
//this is the final callback of the nested(2nd) async.series call
callback(); //this is the iterator callback of func3,this will now call the final callback of the original async.series
});
}], function (err) {
//final callback after all the functions are executed.
return callback_foo();//call your foo's callback.
});
}
Note:callback used in func1,2,3,4,5 need not be defined,its async.series's iterator callback,thats helps us to move to the next function.
However i don't see the point of nested async.series calls.you could do it with 1 async.series call.
var foo = function (callback_foo) {
async.series([func1, func2, func3,func4,func5], function (err) {
if (err) {
return callback_foo(err)
}
});
};

Categories