I want to render JavaScript function in every 500ms using node Cronjobs.
But I could find function for every 1 second as below.
cron.schedule("*/1 * * * * *", function() {
console.log("running a task every 1 second");
});
Is there anyway to run function on every 500ms using node Cronjob?
Setting a cron job to execute that frequently is not possible, and for good reason - a task executing that frequently shouldn't be done using a cron.
Instead, you can use Timers with Node.js:
function myFunc(arg) {
console.log("Argument received: " + arg);
}
setTimeout(myFunc, 500, "some message"); // Executes every 500ms.
Timers can also be instantiated into a variable:
const timeoutObject = setTimeout(() => {
console.log("I will print every 500ms!");
}, 500);
clearTimeout(timeoutObject);
Related
When I run this code in Firefox and Chrome, the results are different:
function run() {
setTimeout(() => console.log("1"), 0);
setTimeout(() => console.log("2"), 100);
let start = Date.now();
while (Date.now() - start < 200) {
// do nothing
}
setTimeout(() => {
console.log("3");
}, 0);
start = Date.now();
while (Date.now() - start < 200) {
// do nothing
}
setTimeout(() => {
console.log("4");
}, 0);
}
run();
In Chrome (and Node.js), this is printed:
1
3
2
4
In Firefox, this is printed:
1
2
3
4
But if I remove the line 2 (setTimeout(() => console.log("1"), 0);), then the same thing is printed on every platform:
2
3
4
How to explain these different results?
Thanks!
The explanation: It doesn't matter.
The details of when deferred "messages" are added to the event loop message queue are implementation details, not documented guarantees. By the time your function yields control back to the event loop, all of your setTimeout call are eligible to execute (three of them were scheduled to run immediately, one of them was scheduled to run in 100 ms) and you've guaranteed it's been at least 400 ms since you scheduled it.
The difference between the two could be as simple as whether they choose to look for deferred tasks that have become ready (to move from the deferred queue to the main "ready to go" message queue) immediately before or immediately after new items are inserted in the main message queue. Chrome chooses to move immediately after 3 is scheduled (so 3 goes in, then the deferred 2), Firefox immediately before (moving in 2 before it puts 3 in).
Both of them could change in the next release without violating any documented guarantees. Don't rely on it, don't expect it to be stable. While immediately scheduled tasks are guaranteed to execute in FIFO order, there are no guarantees on when deferred tasks get moved onto the "ready-to-go" message queue. The spec seems to requires that 1, 3 and 4 execute in that order (since they were all immediately ready, not deferred), with only the ordering of 2 being flexible, but even that isn't a true guarantee; it can get weird with the various ways in which an "immediate" setTimeout task may not actually be scheduled immediately.
You may be interested in the MDN docs on why setTimeout can take longer than expected; it explains by side-effect a lot of how the event loop works, even as it carefully provides no guarantees on the details you're exploring.
I can't give you an full detailed explanation, but the second paramter of setTimeoput and setInterval doesn't mean, it will exactly execute it at that time. They will put it in a queue, so the background can execute it.
The browser has a lifecycle when to execute specific steps to update the data and the styles.
I can only send you this youtube link, that helped me to learn more about it:
https://www.youtube.com/watch?v=MCi6AZMkxcU
1, 2, 3, 4 is the behavior that is expected.
The specs ask to
Wait until any invocations of this algorithm that had the same global and orderingIdentifier, that started before this one, and whose milliseconds is equal to or less than this one's, have completed.
So any call to setTimeout that were both made before, and had their milliseconds set to a lower value should be called first.
Firefox, Safari, and the current stable channel of Chrome all do this.
So when the event loop gains control again, it sees that all the timers are ready to be called, and it queues tasks for each, in this scheduled called order:
"1": scheduled-time = t=0 + 0 = 0
"2": scheduled-time = t=0 + 100 = 100
"3": scheduled-time = t=200 + 0 = 300
"4": scheduled-time = t=400 + 0 = 400
But, what Chrome apparently used to do and still does in its other branches is that they only do look at the milliseconds param to do the ordering and ignore the first "that started before this one" condition.
So in there we've got,
"1": milliseconds = 0
"3": milliseconds = 0
"4": milliseconds = 0
"2": milliseconds = 100
Below is a rewrite of this logic:
// We use a MessageChannel to hook on each iteration of the event loop
function postTask(cb) {
const channel = postTask.channel ??= new MessageChannel();
const { port1, port2 } = channel;
port1.addEventListener("message", (evt) => { cb() }, { once: true });
port1.start();
port2.postMessage("");
}
const timers = new Set();
let ended = false; // So we can stop our loop after some time
function timeoutChecker() {
const now = performance.now();
const toCall = Array.from(timers)
.filter(({ startTime, millis }) => startTime + millis <= now)
.sort((a, b) => a.millis - b.millis);
while(toCall.length) {
const timer = toCall.shift();
timers.delete(timer);
timer.callback();
}
if (!ended) {
postTask(timeoutChecker);
}
}
function myTimeout(callback, millis) {
const startTime = performance.now();
timers.add({ startTime, millis, callback });
}
// Begin our loop
postTask(timeoutChecker);
// OP's code
function run() {
myTimeout(() => console.log("1"), 0);
myTimeout(() => console.log("2"), 100);
let start = Date.now();
while (Date.now() - start < 200) {
// do nothing
}
myTimeout(() => {
console.log("3");
}, 0);
start = Date.now();
while (Date.now() - start < 200) {
// do nothing
}
myTimeout(() => {
console.log("4");
}, 0);
}
run();
// all should be done after 1s
setTimeout(() => ended = true, 1000);
As for why you sometimes may see "2" before "4" in Chrome and node.js, it's because they do clamp 0ms timeout to 1ms (thought they're working on removing this in Chrome). So when the event loop gains control at t=400, this log("4") timeout may not have met the timer condition yet.
Finally about Chrome's branch thing, I must admit I'm not sure at all what happens there. Running a bisect (against Canary branch) I couldn't find a single revision where the current stable branch behavior happens, so this must be a branch settings thing.
I have this function. Basically it searches data from database and does something with it. In this demo it just increases counter.
exports.fullThreads = function(){
return new Promise((resolve, reject) => {
MongoClient.connect(mongoUrl, (err, db) => {
var fullThreads = db.collection('tmp_fullThreads'),
threadPages = db.collection('tmp_threadPages').find();
var counter = 0;
threadPages.on('data', (doc) => {
setTimeout(function(){
counter++;
}, 200)
});
threadPages.on('end', () => {
console.log('end');
console.log(counter);
});
});//connect
});//promise
}//fullthreads
In this example I expected that it would call for data, wait 200ms, and then increase counter. Once it reaches the end, it would end. However it is different. on('end') is called before on('data') actually finished. I guess that is because it didn't return value immediately. So this setTimeout function is not a way to go. However I have a real problem here. This is simply way too fast and in real life code, this wouldn't increase counter, it would call foreign API which doesn't accept so many calls in so little time, so I wanted to make a delay between each call, how is this done properly?
Then you would need some kind of queu
eg:
queuTasks = [];
queuTasks.push("Task1");
queuTasks.push("Task2");
function doTasks(){
// Do your task
if(queuTasks.length > 0){
console.log(queuTasks[0]);
queuTasks.splice(0,1); // Remove it from the queu
}
setTimeout(function(){ doTasks();}, 1000);
}
This is just some quick code i made, may not work out of the box. But think you get the idea.
I know this is not entirely what you were asking about
This is my workaround:
var threadPages = db.collection('tmp_threadPages').find();
var delay = 0;
function test(doc, delay){
setTimeout(function(){
console.log(delay);
}, delay)
}
threadPages.on('data', (doc) => {
test(doc, delay);
delay += 100;
});
It works well if you do not need to bind proper events to on('end method. Basically it increases delay per request, otherwise it would fire all of them at once. This makes code go slower and it wouldn't overkill API with too many requests per second.
In my code, I'm trying to put a certain delay before continuing to the rest of the code. Pretty basic. I'm using a custom sleep function because javascript's native sleep function is not working at all. I'm actually working in app script in google spreadsheets so maybe that's why. But the following code is in the <script> tag of the html file in spreadsheet app script.
Anyway, when I use sleep(), it is being executed before the setTimeout
function get_ids(db){
window.alert("before window.ids is saved?");
google.script.run.withSuccessHandler(getIdsFromAppscript).getIdsFromModel(db);
//this returns a result to getIdsFromAppscript but the following code doesn't wait
//for the result to be returned so I want to use sleep before the ids
//variable is returned by get_ids
setTimeout(function(){
window.alert("checking if ids is saved after 10s?");
window.alert("In timeout ids="+window.ids);
var ids= window.ids; //is non empty
},10000);
sleep(10000);
var ids= window.ids;
window.alert("after wait");
window.alert("after sleep ids="+ids); //is empty but should be non empty
return ids; //=window.ids , Need to return a non-empty result
}
function getIdsFromAppscript(result){
window.ids=result;
}
and the sleep function:
function sleep(ms) {
var start = new Date().getTime(), expire = start + ms;
while (new Date().getTime() < expire) { }
return;
}
Current Order of output based on window.alert():
1) before window is saved?
2) after sleep
3) after sleep ids= //basically empty which shouldn't be the case
4) checking if ids is saved after 10s?
5) In timeout ids= [.....] //non empty list
However, my desired output order is:
1) before window is saved?
2) checking if ids is saved after 10s?
3) In timeout ids= [.....] //non empty list
4) after sleep
5) after sleep ids= [...] //should be a non empty list
The reason why I'm writing setTimeout is to show that after 10 seconds, the result is being stored in window.ids however even after I give a sleep for 10 seconds, or even 30 seconds, I can't get the result from window.ids.
What exactly am I doing wrong here? Thanks in advance~
Java Script, especially through the V8 engine does not sleep. Sleeping causes the entire thread that JavaScript runs on to stop, which breaks the whole point of asynchronocy. setTimeout() only waits to run the function you push into it for the time you also put into it. It doesn't stop the rest of the executions, and whatever happens first will happen first.
If it's important to you that something happens in order, always, then you need to use callbacks or promises.
An example in code could be:
function doTimeout(ms) {
setTimeout(function(){
window.alert("checking if ids is saved after 10s?");
window.alert("In timeout ids="+window.ids);
var ids= window.ids; //is non empty
},ms);
}
function sleep(ms, callback) {
var start = new Date().getTime(), expire = start + ms;
while (new Date().getTime() < expire) { }
callback(ms);
}
sleep(10000, doTimeout);
Javascript is single threaded. You must return from your code for scripts in other threads to execute. Script in other threads includes functions to handle a timeout event, functions called when promises are kept or fail, and call back functions provided for asynchronous requests made using an XMLHttpRequest object.
Writing a function and calling it sleep() does not change this. You could have called it waitingForGodot() for all the difference it would make. What the code you provided does is to spend a lot of time looping in the thread it was called in. It does not relinquish control and blocks all other scripts from executing. If it goes on for long enough my browser will ask me if I wish to abort the (as in your) script.
I have included two examples below showing that your sleep function blocks the entire Javascript engine. When I use your sleep function, the interval function does not get executed even though I have set an interval of 100 ms and the output is delayed by 10 seconds. However, in the second example the output does get printed immediately at the correct interval. This shows your sleep function is blocking the entire execution engine and that explains why your ids array is empty.
function sleep(ms) {
var start = new Date().getTime(),
expire = start + ms;
while (new Date().getTime() < expire) {}
return;
}
function get_ids() {
document.write("before window.ids is saved?" + "<br>");
var counter = 0;
setInterval(function() {
while (counter < 100) {
document.write("checking if ids is saved after 10s?" + "<br>");
counter = counter + 1
}
}, 100);
sleep(10000);
documen.write("after wait");
}
document.write("Start");
get_ids()
document.write("End");
In this example I have commented out your sleep function and as expected the output gets printed every 100 ms:
function sleep(ms) {
var start = new Date().getTime(),
expire = start + ms;
while (new Date().getTime() < expire) {}
return;
}
function get_ids() {
document.write("before window.ids is saved?" + "<br>");
var counter = 0;
setInterval(function() {
while (counter < 100) {
document.write("checking if ids is saved after 10s?" + "<br>");
counter = counter + 1
}
}, 100);
//sleep(10000);
documen.write("after wait");
}
document.write("Start");
get_ids()
document.write("End");
I have the following scenario:
I have a javascript ajax function loadCars() that needs to be called after the page loads in 10 seconds, and then every 60 seconds.
The below is what I have tried so far:
setTimeout(function(){setInterval(function(){loadCars()}, 60000)}, 10000);
What is happening is that the function is being called after 10 seconds but never again, what am I missing?
You need to call loadCars on setTimeout and on setInterval.
setTimeout(function() {
console.log('first 10 secs');
// loadCars();
setInterval(function() {
console.log('60 secs has passed');
// loadCars();
}, 60000);
}, 10000);
console.log('page loaded');
I don't agree with the answers given because they use setInterval or don't wait for the ajax call to be finished. IMO your should set a new timeout only when the function loadcars (and the ajax call) has finished.
Example:
function loadCars () {
// ajax call happens here
$.ajax()
.then(function(){
// call the function here
setTimeout(function(){
loadCars();
// wait a minute after you recieved the data
}, 60000)
})
}
// wait 10 seconds
setTimeout(function(){
loadCars();
}, 10000)
The advantage if this is that it will only start setting a new timeout when the HTTP request is finished and prevent the function from getting out of sync. If you use setinterval in combination with an ajax call then the next ajax call will happen in 60 seconds even if the current one is delayed for 10 seconds (and you don't want that).
You can call setTimeout(loadCars, 60000) in your loadCars() method that way you call it once initially with setTimeout 10 seconds then from that point it sets a timeout for 1 minute out every time it executes...
function loadCars()
{
//code
setTimeout(loadCars, 60000);
}
setTimeout(loadCars, 10000);
If you want the next timeout to be scheduled only after ajax call is completed then either make a synchronus ajax call or put the setTimeout() in your success callback of your ajax call...The latter being the better option.
To get more control over timings and function calls you could specify them all this way:
function loadCars() {
$('#log').append('Cars loaded<br />');
};
function loadManufacturers() {
$('#log').append('Manufacturers loaded<br />');
};
function loadCustomers() {
$('#log').append('Customers loaded<br />');
};
function loadContent(delays, functions) {
if (functions.length) {
setTimeout(function () {
functions.pop()();
loadContent(delays, functions);
}, delays.pop());
};
};
loadContent([3000, 2000, 1000], [loadCars, loadManufacturers, loadCustomers]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p id="log"></p>
Playground
I'm working on a chat application, which polls the server at a timeout.
The timeout increases if, over time, there hasn't been any recent activity.
The function loadNew() performs an ajax call to the server, which responds with message data.
pollTimeoutTime = 500;
function poll() {
pollTimeout = setTimeout(function(){
loadNew();
if (!new_messages_count) {
//Increasing delay between polls as no messages are incoming to a maximum of 1 minute/60 seconds
if (pollTimeoutTime < 60000) pollTimeoutTime = pollTimeoutTime * 1.25;
}
else {
//Reset delay between poll to default of 0.5 seconds
pollTimeoutTime = 500;
}
poll();
},pollTimeoutTime);
}
The problem I'm having is that the timeout function does not wait for the function loadNew() to complete, which causes the same poll to be sent twice or more if the timeout is lower than the time it takes for the ajax call in the function to complete.
The server thus responds with the same data multiple times, which leads to duplicative display of messages in the chat.
Is there a way to make the timeout only trigger after loadNew() has finished fetching and displaying the data?
EDIT: after using #Brad M's answer, it doesn't duplicate messages anymore. I would still like to have a way to call for a poll after the user submits a message, so the new message is displayed immediately. This would interfere with the timeout set in loadNew(), which would cause messages to be duplicated again. Could you think of a way to get that working?
Without seeing your loadNew function, an easy fix might be to change that function to return your ajax call (return $.ajax({...});) and change the code you posted to this:
pollTimeoutTime = 500;
function poll() {
pollTimeout = setTimeout(function () {
loadNew().done(function (result) {
if (!new_messages_count) {
//Increasing delay between polls as no messages are incoming to a maximum of 1 minute/60 seconds
if (pollTimeoutTime < 60000) pollTimeoutTime = pollTimeoutTime * 1.25;
} else {
//Reset delay between poll to default of 0.5 seconds
pollTimeoutTime = 500;
}
poll();
});
}, pollTimeoutTime);
}
Use ajax callback functions such as success or complete to trigger a new poll.