I am using node js with the node-cron library. I need to make a delay in executing the code inside the cron. I tried await and setInterval, but the second cron function is not executed. What can be done?
cron.schedule("*/10 * * * * *", async function() {
FakeGames.StartGame();
await wait(3000);
FakeGames.StopGame()
});
You can use settimeout, like this, so your FakeGames.stopGame() will execute after a certain dealy
cron.schedule("*/10 * * * * *", function () {
return new Promise((resolve, reject) => {
FakeGames.StartGame();
setTimeout(() => {
FakeGames.StopGame();
resolve();
}, delayInMilliSeconds);
});
});
Related
I have to run an async function written with Puppeteer (it's a bot) and I want to run that function every 60 seconds. The issue is that the async function (bot) runs for 2 min and so node cron automatically executes another async function which leads to 2 bot and 5s later it will launch another instance of this function.
What i want is to run 1st time then wait for 60s And after that execute it again. I'm so confused, it's my first NodeJS project.
const cron = require("node-cron")
cron.schedule("*/60 * * * * *", async () => {
try {
console.log(BotVote("Royjon94", "1"))
}
catch {
console.log('error 404')
}
})
I'm not sure cron is suitable for this kind of job. But basically you can achieve the same behavior with a basic while loop and a promise to await.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function BotVote() {
await new Promise(r => setTimeout(() => {
console.log("voting");
r();
})) // for illusturation purpose
}
async function worker() {
let i = 0;
let keepGoing = true;
while (keepGoing) {
await BotVote()
await delay(600); // imagine it's 1minute.
i++;
if (i === 3) keepGoing = false; // decide when you stop
}
}
worker();
I (first time JavaScript user since yesterday) managed to get JavaScript to run functions in sequential execution order (see code below) (credit to #CertainPerformance). I need to use the fastFunction in multiple slowFunctions. The current solution does not seem DRY (do not repeat yourself) to me and at the same time it does not guarantee the exectution order of slowFunction1 and then slowFunction2. What is the DRY solution to this problem in JavaScript? Can I force JavaScript to always run in sequential mode by some configuration? Using nested callbacks does not seem to be the most intelligent solution to me.
function fastFunction(message) {
console.log(message);
}
function slowFunction1(callback, message) {
setTimeout(() => {
console.log('slowFunction1!');
callback(message);
}, 10000);
}
function slowFunction2(callback, message) {
setTimeout(() => {
console.log('slowFunction2!');
callback(message);
}, 1000);
}
slowFunction1(fastFunction, 'fast_Function');
slowFunction2(fastFunction, 'fast_Function');
With async/await you can sequence asynchronous tasks as follows:
// Very handy utility function to get a promise that resolves after a given delay
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function fastFunction(message) {
console.log(message);
}
async function slowFunction1(callback, message) {
console.log('slowFunction1!');
await delay(2000); // two seconds
callback(message);
}
async function slowFunction2(callback, message) {
console.log('slowFunction2!');
await delay(1000); // one second
callback(message);
}
(async function() {
// Put all your logic here, and await promises...
await slowFunction1(fastFunction, 'fast_Function');
await slowFunction2(fastFunction, 'fast_Function');
})(); // execute immediately
Now you will have the delays happening one after the other completes, so 2+1=3 seconds in (approximate) total execution time.
This mimics most what you had as pattern, but once you are using promises, you don't need the callback pattern anymore and can do it like this:
// Very handy utility function to get a promise that resolves after a given delay
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function fastFunction(message) {
console.log(message);
}
(async function() {
console.log('slow part 1');
await delay(2000); // two seconds
fastFunction('fast_function');
console.log('slow part 2');
await delay(1000); // one second
fastFunction('fast_function');
})(); // execute immediately
I would like to execute half of the a function and wait 1 second or 2 and then execute the rest, I tried like this, but I don't understand how to put a function inside another.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
$('#music_action').click(function() {
if($(menu_start_animation).hasClass('menu_start_animation')) {
$(menu_start_animation).removeClass('menu_start_animation');
$(menu_start_animation).addClass('favorites_back_animation');
await sleep(2000);
$(menu_start_animation).removeClass('favorites_back_animation');
$(menu_start_animation).addClass('music_animation');
}
});
You just need to make your click callback async.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
$('#music_action').click(async function () {
if ($(menu_start_animation).hasClass('menu_start_animation')) {
$(menu_start_animation).removeClass('menu_start_animation');
$(menu_start_animation).addClass('favorites_back_animation');
await sleep(2000);
$(menu_start_animation).removeClass('favorites_back_animation');
$(menu_start_animation).addClass('music_animation');
}
});
If you want to accomplish this using await, you should to make the function asynchronous or it will throw a syntax error, await wont work using regular functions. Here is an example of how to accomplish what you're trying to do asynchronously.
sleep = async (ms) => {
await new Promise((resolve, reject) => setTimeout(resolve, ms));
}
onClick = async () => {
console.log('first task')
// wait 2 seconds
await sleep(2000);
console.log('second task')
}
onClick()
However, for this use case you might not need to accomplish this asynchronously. Using setTimeout() seems async, but it runs concurrently in the background and uses less memory - asynchronous functions break a synchronous flow, but they don't necessarily execute in a concurrent order. In your case, it might be best to use a callback function.
/**
* Basic example updating a string
* In your case, the callback function would be adding and removing whatever you
* needed to in the second half of your function
*/
let word = 'init'
function sleep (callback, ms) {
setTimeout( () => {
word = 'updatedWord'
callback()
}, ms)
}
sleep(function () {
alert(word)
}, 2000)
How we can end an async function from a callback passed to an event emitter without promisifing the event emitter?
Also without using external modules, just plain NodeJS 7.x/8.x (Which supports Es6 syntax and async/await.
We want basically to mix an async function ... with an event emitter, so that it resolves when the event emitter signals end.
Also bear in mind that we won't start with the event emitter until done with some other async functions, using await.
If we had a "new Promise(...)" we would call resolve(); and the headache would be over, but in 'async' there's no 'resolve', plus we cannot use 'return' because we're inside a callback.
/*
* Example of mixing Events + async/await.
*/
// Supose a random pomise'd function like:
function canIHazACheezBurger () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(Math.random() > 0.5);
}, 500 + Math.random() * 500)
});
}
/**
* Then, we want to mix an event emitter with this logic,
* what we want is that this function resolves the promise
* when the event emitter signals 'end' (for example).
* Also bear in mind that we won't start with the event emitter
* until done with the above function.
* If I had a "new Promise(...)" I would call resolve(); and the
* headache would be over, but in 'async' there's no 'resolve',
* plus I cannot use 'return' because I'm inside a callback.
*/
async function bakeMeSomeBurgers () {
let canIHave = await canIHazACheezBurger();
// Do something with the result, as an example.
if (canIHave) {
console.log('Hehe, you can have...');
} else {
console.log('NOPE');
}
// Here invoke our event emitter:
let cook = new BurgerCooking('cheez');
// Assume that is a normal event emitter, like for handling a download.
cook.on('update', (percent) => {
console.log(`The burger is ${percent}% done`);
});
// Here lies the problem:
cook.on('end', () => {
console.log('I\'ve finished the burger!');
if (canIHave) {
console.log('Here, take it :)');
} else {
console.log('Too bad you can\'t have it >:)');
}
// So, now... What?
// resolve(); ? nope
// return; ?
});
}
Disclaimer
I want to apologize if this question is already done somewhere. The research done shows questions related to mix async with sync logic, but I've found nothing about this.
A similar question in title is this 'write async function with EventEmitter' but it has nothing to do with this question.
Can we end an async function from a callback passed to an event emitter without promisifing the event emitter?
No. async/await syntax is just sugar for then calls and relies on promises.
async function bakeMeSomeBurgers () {
let canIHave = await canIHazACheezBurger();
if (canIHave)
console.log('Hehe, you can have...');
else
console.log('NOPE');
// Here we create and await our promise:
await new Promise((resolve, reject) => {
// Here invoke our event emitter:
let cook = new BurgerCooking('cheez');
// a normal event callback:
cook.on('update', percent => {
console.log(`The burger is ${percent}% done`);
});
cook.on('end', resolve); // call resolve when its done
cook.on('error', reject); // don't forget this
});
console.log('I\'ve finished the burger!');
if (canIHave)
console.log('Here, take it :)');
else
console.log('Too bad, you can\'t have it >:)');
}
I am building an app that must poll remote devices (generator fn sendRequests()) every 2 seconds.
What's the right way to call the generator fn using setInterval, which isn't a generator and doesn't yield
function * sendRequests() {
// multiple remote async requests are sent
}
var timer = setInterval(() => {
// yield sendRequests()
}, 2000)
The problem with yielding from the setInterval callback is that yield can only yield to the generator function* that immediately contains it. Therefore, you can't yield from a callback.
What you can do from a callback is resolve a Promise, which your generator function can yield:
async function* pollGen() {
yield new Promise((resolve, reject) => {
setInterval(() => resolve(...), 2000);
});
The problem with that is a Promise can only be settled once. Therefore, calling resolve every 2000ms won't do anything beyond the first call.
What you can do instead is call setTimeout repeatedly, in a while loop:
async function* pollGen() {
let i = 0;
while (i < 10)
yield new Promise((resolve, reject) => {
setTimeout(() => resolve(i++), 200);
});
}
(async function main() {
// for-await-of syntax
for await (const result of pollGen())
console.log(result);
}());
The new for-await-of syntax has been available since Node v9.2, and can be used in Node v10 or later without any flags.
Since AdonisJS uses co() under the hood, I used #Bergi suggestion of wrapping in co()
function * sendRequests() {
// multiple remote async requests are sent
}
var timer = setInterval(() => {
co(function * () {
yield sendRequests()
})
}, 2000)