Call a async function every minute for 5 minutes in nodejs - node.js

I am trying to call a async function every minute for 5 minutes before exiting the main function. Below is the print_data() function which I am calling in main() function.
var print_data = async () => {
console.log("Hello")
}
async function main() {
process.stderr.write("--Start--")
var data = await print_data()
console.log(data)
}
main()
Very new to writing async function. What is the best way to call print_data function every minute for 5 minutes and print the output each minute? I tried something using setInterval and was not able to execute the function completely.
Any help would be good. Thank you in advance.

This is one way to do it using setInterval and clearInterval. Read more about it here: https://nodejs.org/api/timers.html#timers_clearinterval_timeout
Using IIFE to prevent polluting of the global scope.
(function (){
let counter = 0; //counter to keep track of number of times the setInterval Cb is called
let data; // to store reference of Timeout object as returned by setInterval, this is used in clearInterval
const print_data = async () => {
console.log("Hello")
counter++;
if (counter == '5') {
clearInterval(data);
}
}
async function main() {
process.stderr.write("--Start--")
data = setInterval(print_data, 1000*60); //60 seconds
}
main();
})();

Please check if the below code can be a solution.
var print_data = async () => {
console.log("Hello")
return "Hello";
}
var call_print_data = () => new Promise((resolve, reject) => {
var count = 0;
var interval = setInterval(async () => {
var res = await print_data();
count += 1;
if (count === 5) { // if it has been run 5 times, we resolve the promise
clearInterval(interval);
resolve(res); // result of promise
}
}, 1000 * 60); // 1 min interval
});
async function main() {
process.stderr.write("--Start--")
var data = await call_print_data(); // The main function will wait 5 minutes here
console.log(data)
}
main()

Related

NodeJS - return response as a process continue working anyways

I have an async method which invokes a few calls (await promise....) in a loop,
and eventually returns a result.
When I get the result from that function, I send back a response to the client.
What I have to do is to return a response in the middle of the process/loop,
while the loop continue running.
Of course it breaks the loop, since it returns from the function in the middle of the loop.
Here is a piece of code to demonstrate.
app.post('/test', async (req, res)=>{
const body = JSON.stringify(req.body)
await doSomething()
res.status(200).send("ok");
});
const doSomething = async () => {
let times = 0;
for(let i=0 ; i<5 ; i++){
console.log(i)
await delay(1000);
if(i==2){
return 2;
}
}
return times;
}
const delay = async (ms) => {
return await new Promise(resolve => setTimeout(resolve, ms));
}
When I get i==2, I want to return a value and response to the client,
but I still want the loop to run till the end.
I thought to use some observer which will be responsible for returning a response,
(say rxjs, event emitter, etc...). Not sure what is the best practice for such
a different situation.
Thanks for any advice.
The solution is to use a synchronous function and return a Promise. But AFAIK making the callback passed to the Promise constructor async won't work:
const doSomething = () => {
let times = 0;
return new Promise(async (resolveMain) => {
for(let i=0 ; i<5 ; i++){
console.log(i)
await delay(1000);
if(i==2){
resolveMain(2);
}
}
});
}
It's also twisted LOL.
So I'm sure there are many other ways to accomplish this, but I'm assuming you want to keep the await delay(1000);. What you're gong to need is an async generator function.
app.post('/test', async (req, res)=>{
const body = JSON.stringify(req.body)
await doSomething()
res.status(200).send("ok");
});
async function* doLoopyThing(){
let times = 0;
for(let i=0 ; i<5 ; i++){
console.log(i)
await delay(1000);
if(i==2){
yield 2;
}
}
}
function doSomething(){
return new Promise(resolve => {
const looper = doLoopyThing();
looper.next().then(({value}) => resolve(value));
looper.next();
}
}
This is also twisted, but it should work.
I don't understand how this can possibly be the right way to actually accomplish something. But I'm assuming the is just for fun, or you're trying to learn.
Also if all you were trying to show with the await delay(1000) was a heavy function, and you don't actually need the function to be asynchronous, the first solution should work.

Asynchronous function not waiting for Promise

I've written following asynchronious node.js function, which accesses to my database via Mongoose and thus is an async function):
function getWindSpeed(householdID){
return new Promise(async function (resolve, _){
const household = await Household.findById(householdID)
resolve(stoch.norm(household.windSimulation.mu, household.windSimulation.sigma, 1))
})
}
In the other hand, I have following function, which is also async because both accesses to the database and uses the previous function for each element in the database:
async function getMeanWindSpeed() {
return new Promise(async function (resolve, reject){
let numberOfHouseholds = 0
let averageWind = 0.0
console.log('Begin')
await Household.find({}, async function (error, households) {
if(error){
reject(error)
}else{
numberOfHouseholds = households.length
for(let i = 0; i < households.length; i++){
const speed = await wind.getWindSpeed(households[i].id)
console.log(speed)
averageWind += speed
}
}
})
averageWind = averageWind / numberOfHouseholds
console.log('Finish')
resolve(averageWind)
})
}
As you can see, I iterate over all the elements in the collection and apply the getWindSpeed() function, however it doesn't wait for its completion, as I get the following trace based on the console.log(...) debug messaged:
Begin
Finish
12.2322
23.1123
(more speeds)
...
Some more information that may be usefuk:
I'm awaiting for the result of getMeanWindSpeed() in another async function
I tried to return one hardcoded value for each element in the database (instead of calling getWindSpeed() and it worked fined, so I guess the problem is in that function.
Thanks in advance
If we don't pass a callback to .find() we'll get a promise returned, this makes the code a lot easier to read.
We could further simplify the function getMeanWindspeed since it becomes a simple wrapper for getAverageWindSpeed();
For example:
async function getAverageWindspeed() {
let numberOfHouseholds = 0
let averageWind = 0.0
let households = await Household.find({});
numberOfHouseholds = households.length
for(let i = 0; i < households.length; i++){
const speed = await wind.getWindSpeed(households[i].id)
console.log(speed)
averageWind += speed
}
return averageWind / numberOfHouseholds;
}
async function getMeanWindSpeed() {
console.log('Begin')
let averageWind = await getAverageWindspeed();
console.log('Finish')
return averageWind;
}
Why you are mixing await with promise. It is bad practice. If you can do same thing using await and async. See the below example.
const fakeDelay = () => new Promise(r => {
setTimeout(() => r("data"), 1000);
})
const Household = {
findById: () => fakeDelay()
}
async function getWindSpeed(householdID){
const household = await Household.findById(householdID)
console.log()
//stoch.norm(household.windSimulation.mu, household.windSimulation.sigma, 1)
return household;
}
const main = async () =>{
getWindSpeed().then(console.log)
}
main()
// notice
async function getWindSpeed
will be by default promise

async await with setInterval

function first(){
console.log('first')
}
function second(){
console.log('second')
}
let interval = async ()=>{
await setInterval(first,2000)
await setInterval(second,2000)
}
interval();
Imagine that I have this code above.
When I run it, first() and second() will be called at the same time; how do I call second() after first)() returns some data, for example, if first() is done, only then call second()?
Because first() in my code will be working with a big amount of data and if this 2 functions will be calling at the same time, it will be hard for the server.
How do I call second() each time when first() will return some data?
As mentioned above setInterval does not play well with promises if you do not stop it. In case you clear the interval you can use it like:
async function waitUntil(condition) {
return await new Promise(resolve => {
const interval = setInterval(() => {
if (condition) {
resolve('foo');
clearInterval(interval);
};
}, 1000);
});
}
Later you can use it like
const bar = waitUntil(someConditionHere)
You have a few problems:
Promises may only ever resolve once, setInterval() is meant to call the callback multiple times, Promises do not support this case well.
Neither setInterval(), nor the more appropriate setTimeout() return Promises, therefore, awaiting on them is pointless in this context.
You're looking for a function that returns a Promise which resolves after some times (using setTimeout(), probably, not setInterval()).
Luckily, creating such a function is rather trivial:
async function delay(ms) {
// return await for better async stack trace support in case of errors.
return await new Promise(resolve => setTimeout(resolve, ms));
}
With this new delay function, you can implement your desired flow:
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let run = async ()=>{
await delay(2000);
first();
await delay(2000)
second();
}
run();
setInterval doesn't play well with promises because it triggers a callback multiple times, while promise resolves once.
It seems that it's setTimeout that fits the case. It should be promisified in order to be used with async..await:
async () => {
await new Promise(resolve => setTimeout(() => resolve(first()), 2000));
await new Promise(resolve => setTimeout(() => resolve(second()), 2000));
}
await expression causes async to pause until a Promise is settled
so you can directly get the promise's result without await
for me, I want to initiate Http request every 1s
let intervalid
async function testFunction() {
intervalid = setInterval(() => {
// I use axios like: axios.get('/user?ID=12345').then
new Promise(function(resolve, reject){
resolve('something')
}).then(res => {
if (condition) {
// do something
} else {
clearInterval(intervalid)
}
})
}, 1000)
}
// you can use this function like
testFunction()
// or stop the setInterval in any place by
clearInterval(intervalid)
You could use an IFFE. This way you could escape the issue of myInterval not accepting Promise as a return type.
There are cases where you need setInterval, because you want to call some function unknown amount of times with some interval in between.
When I faced this problem this turned out to be the most straight-forward solution for me. I hope it help someone :)
For me the use case was that I wanted to send logs to CloudWatch but try not to face the Throttle exception for sending more than 5 logs per second. So I needed to keep my logs and send them as a batch in an interval of 1 second. The solution I'm posting here is what I ended up using.
async function myAsyncFunc(): Promise<string> {
return new Promise<string>((resolve) => {
resolve("hello world");
});
}
function myInterval(): void {
setInterval(() => {
void (async () => {
await myAsyncFunc();
})();
}, 5_000);
}
// then call like so
myInterval();
Looked through all the answers but still didn't find the correct one that would work exactly how the OP is asked. This is what I used for the same purpose:
async function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (await callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})()
In my example, I also put interval iteration count and the timer itself, just in case the caller would need to do something with it. However, it's not necessary
In my case, I needed to iterate through a list of images, pausing in between each, and then a longer pause at the end before re-looping through.
I accomplished this by combining several techniques from above, calling my function recursively and awaiting a timeout.
If at any point another trigger changes my animationPaused:boolean, my recursive function will exit.
const loopThroughImages = async() => {
for (let i=0; i<numberOfImages; i++){
if (animationPaused) {
return;
}
this.updateImage(i);
await timeout(700);
}
await timeout(1000);
loopThroughImages();
}
loopThroughImages();
Async/await do not make the promises synchronous.
To my knowledge, it's just a different syntax for return Promise and .then().
Here i rewrote the async function and left both versions, so you can see what it really does and compare.
It's in fact a cascade of Promises.
// by the way no need for async there. the callback does not return a promise, so no need for await.
function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
// async function with async/await, this code ...
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})() //... returns a pending Promise and ...
console.log('i do not wait');
// ... is kinda identical to this code.
// still asynchronous but return Promise statements with then cascade.
(() => {
console.log('start again');
return waitInterval(first, 1000).then(() => {
return waitInterval(second, 1000).then(() => {
console.log('finish again');
});
});
})(); // returns a pending Promise...
console.log('i do not wait either');
You can see the two async functions both execute at the same time.
So using promises around intervals here is not very useful, as it's still just intervals, and promises changes nothing, and make things confusing...
As the code is calling callbacks repeatedly into an interval, this is, i think, a cleaner way:
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function executeThroughTime(...callbacks){
console.log('start');
let callbackIndex = 0; // to track current callback.
let timerIndex = 0; // index given to callbacks
let interval = setInterval(() =>{
if (callbacks[callbackIndex](timerIndex++)){ // callback return true when it finishes.
timerIndex = 0; // resets for next callback
if (++callbackIndex>=callbacks.length){ // if no next callback finish.
clearInterval(interval);
console.log('finish');
}
}
},1000)
}
executeThroughTime(first,second);
console.log('and i still do not wait ;)');
Also, this solution execute a callback every secondes.
if the callbacks are async requests that takes more than one sec to resolve, and i can't afford for them to overlap, then, instead of doing iterative call with repetitive interval, i would get the request resolution to call the next request (through a timer if i don't want to harass the server).
Here the "recursive" task is called lTask, does pretty much the same as before, except that, as i do not have an interval anymore, i need a new timer each iteration.
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync1(i) {
console.log(`first pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that first big data'), Math.floor(Math.random()*1000)+ 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{
console.log(`first solved: ${i} ->`, result);
return i==2;
});
}
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync2(i) {
console.log(`second pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that second big data'), Math.floor(Math.random()*1000) + 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{ // promise is resolved
console.log(`second solved: ${i} ->`,result);
return i==4; // return a promise
});
}
function executeThroughTime(...asyncCallbacks){
console.log('start');
let callbackIndex = 0;
let timerIndex = 0;
let lPreviousTime = Date.now();
let lTask = () => { // timeout callback.
asyncCallbacks[callbackIndex](timerIndex++).then((result) => { // the setTimeout for the next task is set when the promise is solved.
console.log('result',result)
if (result) { // current callback is done.
timerIndex = 0;
if (++callbackIndex>=asyncCallbacks.length){//are all callbacks done ?
console.log('finish');
return;// its over
}
}
console.log('time elapsed since previous call',Date.now() - lPreviousTime);
lPreviousTime = Date.now();
//console.log('"wait" 1 sec (but not realy)');
setTimeout(lTask,1000);//redo task after 1 sec.
//console.log('i do not wait');
});
}
lTask();// no need to set a timer for first call.
}
executeThroughTime(simulateAsync1,simulateAsync2);
console.log('i do not wait');
Next step would be to empty a fifo with the interval, and fill it with web request promises...

Run 2 repeating async functions without pausing the other on await

so I am trying to run 2 repeating functions which both use async. Both functions at some point use the async await feature. The problem is when one function uses await it pauses both functions. How would I stop this from happening so when one function uses await the other function doesn't pause. Thanks. Example below.
const collectInfo = async () => {
return new Promise(async function(resolve, reject) {
// Collect info from the database then
resolve(data);
});
}
const functionOne = async () => {
timeLeft = 5000;
var timerOne = setInterval(async function(){
if(timeLeft === 0){
var getInfTwo = await collectInfo();
console.log(getInfOne);
startFunctionOne();
clearInterval(timerOne);
}
timeLeft--;
}, 10);
}
const functioTwo = async () => {
timeLeft = 10000;
var timerTwo = setInterval(async function(){
if(timeLeft === 0){
var getInfOne = await collectInfo();
console.log(getInfOne);
startFunctionTwo();
clearInterval(timerTwo);
}
timeLeft--;
}, 10);
}
const startFunctionOne = async () => {
functionOne();
}
const startFunctioTwo = async () => {
functioTwo();
}
startFunctionOne();
startFunctioTwo();
Be carefull, as you haven't us the keyword var or let in functionOne and functionTwo for variable timeLeft, this variable become global, so you use the same global variable in the two functions.
You can't choose when "pause" the function, its automatically done with async, if your two functions are launched in same times and are waiting an input/ouput there's nothing to do.
You need to group these statements in an async function. This way we get two async functions, startFunctionOne() and startFunctionTwo()
Now we take advantage of the event loop to run these async non-blocking functions concurrently.
const functionOnePromise = startFunctionOne()
const functionTwoPromise = startFunctionTwo()
await functionOnePromise
await functionTwoPromise
We have grouped the statements into two functions. Inside the function, each statement depends on the execution of the previous one. Then we concurrently execute both the functions startFunctionOne() and startFunctionTwo()

Stopping an async function without waiting for it to finish

In my system there is an updater function running every few seconds, this function looks something like this:
function updater() {
this.updater = setTimeout(async function() {
let data = await updatingFromInternet(url);
updater();
}, 5000);
}
I call the updater function once and it should update and run itself again 5 seconds after it last updated.
Since the updatingFromInternet function is an async function I can only wait for it to finish and then decide whether or not to keep updating but not stop it at the point it is currently waiting (fetching internet data).
Is there a simple way to stop the update immediately without the need to wait for the async function to return?
Yes as long as you have a reference to the timer handle:
clearTimeout(this.updater)
Instead of updater being a function, I would make it an object. Even with a cancellation featrue, if you called the updater function before the previous one was cancelled, this.updater would be overwritten and you couldn't cancel that timer, it would continue forever.
The below example uses an IIFE to encapsulate its variables and returns an object with a start and stop method.
const elOutput = document.getElementById('output'),
elStatus = document.getElementById('status');
const url = '';
// IIFE that returns the updater object
const updater = (function () {
let timer = null;
let update = function () {
timer = setTimeout(async () => {
elStatus.textContent = 'Waiting for data...';
let data = await updatingFromInternet(url);
// if timer has been set to null, updates have been
// cancelled
if (timer !== null) {
// do something with data here
elOutput.textContent = data;
elStatus.textContent = 'Updating...';
update();
}
}, 5000);
};
let start = () => {
// if the timer is not already running...
if (timer === null) {
elStatus.textContent = 'Starting update timer...';
update();
}
};
let stop = () => {
clearTimeout(timer);
timer = null;
elStatus.textContent = 'Updates Canceled';
};
// return our updater object with its start and stop methods
return {
start,
stop
};
}());
document.getElementById('update').addEventListener('click', updater.start, false);
document.getElementById('cancel').addEventListener('click', updater.stop, false);
// mocking a networks response
const updatingFromInternet = (function () {
let counter = 0;
return function (url) {
return new Promise((res, rej) => {
setTimeout(res.bind(null, counter++), 1000);
});
};
}());
<button type="button" id="update">Update</button>
<button type="button" id="cancel">Cancel updates</button>
<div id="output"></div>
<div id="status"></div>
Even better, since you are using Node, this is the sort of thing that would be ideal to put in a module.
// updater.js
let updatingFromInternet = require('./updatingFromInternet.js');
let timer = null;
let callback = null;
let update = function () {
timer = setTimeout(async () => {
let data = await updatingFromInternet(url);
// if timer has been set to null, updates have been
// cancelled
if (timer !== null) {
callback(data);
update();
}
}, 5000);
};
let start = (userCallback) => {
// if the timer is not already running
// and we received a callback function
if (timer === null && typeof userCallback === 'function') {
callback = userCallback;
update();
}
};
let stop = () => {
clearTimeout(timer);
timer = null;
};
module.exports = {
start,
stop
};
Then, to use it, require it in your main file:
let updater = require('./updater.js');
updater(function (data) {
console.log(data);
}

Resources