Creating a cron job using a while loop - javascript

There are several libraries (especially for NodeJS and Javascript) that allow you to implement cron jobs and subsequently host them on a server.
In essence, cron jobs seem to me nothing more than repetitive tasks that are executed at a specific time/date on a day.
I was wondering therefore what the difference is between these libraries and just let's say a custom while loop. For instance in Javascript we could write:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
My questions are therefore:
why do we use cron job libraries? What are the benefits above a custom function like above?

This would not work as you might expect:
var keepRunning = true
while (keepRunning) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000);
}
That code will schedule new setTimeout callbacks as fast as it can while keepRuning is true, never unwinding the call stack and letting the event loop run any of those callbacks. It will likely consume all of your memory without running the scheduled code even once.
What you can do is something like this:
var keepRunning = true;
function run() {
if (keepRunning) {
// call function to be executed when time constraint satisfied
setTimeout(run, 5000);
}
}
setTimeout(run, 5000);
If you want to schedule all the callbacks at once, then you might do something like this:
for (let i = 1; i <= 100; i++) {
setTimeout(function () {
// call function to be executed when time constraint satisfied
}, 5000 * i);
}
but in this example you need to multiply the timeout by the iteration variable to make sure that they are not scheduled to run at the same time - i.e. they are still scheduled all at once but they are later run at different times.
Remember that JavaScript runs to completion and callbacks are executed later when the call stack unwinds. It's also important that for and while loops block the event loop from executing and no event can be handled while the loop is running.

Cron handles very time specific events far better than this. If you wanted something to happen at 9am each day you would absolutely have to use Cron over some method like this.
Cron measures time from epoch and is the most accurate way of scheduling tasks. I would also imagine it would result in better performance than what you are suggesting.
Why would you NOT use Cron?

A library is a collection of useful code. Those collections tend to group up a significant amount of functions, objects, etc.
Your example was just one situation that had very little versatility. Libraries would provide much more options for your loop, and would go beyond just addressing the rate, but also other factors (depending on what specific library you are referring to).

Related

Allow running setInterval more than once per millisecond in nodejs

I have a node script which is supposed to utilize all the CPU resources a single node process could get. But I found setInterval to be too slow.
And sure enough I found this in the documentation:
When delay is larger than 2147483647 or less than 1, the delay will be
set to 1.
source: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
Now I wonder if there is a way to reduce the limit further or if there is an alternative function that I could use.
I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
Edit:
Again: I can't just use a normal loop because there are other asynchronous things that need to run at the same time.
I'm not sure why this is so hard to understand.
While a normal loop is running, you are blocking the execution of everything else. It doesn't matter if you put the loop in another asynchronously executed function.
What does this mean?
Let's look at some examples:
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
while (true) {
// do whatever
}
What will this code do? It will block everything. console.log('a') will not be executed continuously.
setInterval(()=>{console.log('a')},1000) // asynchronous thing that needs to run in the background
setTimeout(()=>{
while (true) {
// do whatever
}
}, 1)
This will also block the execution of the intervals as soon as the while loop starts.
I believe the question belongs to node rather than to browser. You can use some of the following options (recursively/in loop) for reducing your delay time.
setImmediate
setImmediate - Schedules the "immediate" execution of the callback after I/O events' callbacks. Returns an Immediate for use with clearImmediate().
When multiple calls to setImmediate() are made, the callback functions are queued for execution in the order in which they are created. The entire callback queue is processed every event loop iteration. If an immediate timer is queued from inside an executing callback, that timer will not be triggered until the next event loop iteration.
It's from node guides:
setImmediate and setTimeout are similar, but behave in different
ways depending on when they are called.
setImmediate() is designed to execute a script once the current poll phase completes.
setTimeout() schedules a script to be run after a minimum threshold in ms has elapsed.
process.nextTick
The process.nextTick() method adds the callback to the "next tick
queue". Once the current turn of the event loop turn runs to
completion, all callbacks currently in the next tick queue will be
called.
From node guide
We recommend developers use setImmediate() in all cases because it's
easier to reason about (and it leads to code that's compatible with a
wider variety of environments, like browser JS.)
Thanks to Josh Lin for the idea to just run multiple intervals. I ended up with two simple wrapper functions for setInterval and clearInterval:
function setInterval2(cb,delay) {
if (delay >= 1)
return [setInterval(cb,delay)];
var intervalArr = [];
var intervalCount = Math.round(1/delay);
for (var i=0; i<intervalCount; i++)
intervalArr.push(setInterval(cb,1));
return intervalArr
}
function clearInterval2(intervalArr) {
intervalArr.forEach(clearInterval);
}
It works just like the original functions:
var count = 0;
// run interval every 0.01 milliseconds:
var foo = setInterval2(function(){
count++;
},0.01);
// stop execution:
clearInterval2(foo)
1 setInterval multiple times run more!
let count = 0,
by = 100,
_intervals = [],
timelimit = 100
for (let i = 0; i < by; i++) {
_intervals[i] = setInterval(() => count++, 1)
}
setTimeout(() => {
_intervals.forEach(x => clearInterval(x))
console.log(`count:${count}`)
}, timelimit)
2.setTimeout recurser run less!
let count = 0,
go = true
recurser()
setTimeout(() => {
go = false
console.log(`count:${count}`)
}, 100)
function recurser() {
count++
go && setTimeout(recurser)
}
3.requestAnimationFrame run less!
let count = 0,
go = true,
timelimit = 100
step()
setTimeout(() => {
go = false,
console.log(`count:${count}`)
}, timelimit)
function step() {
count++
go && requestAnimationFrame(step)
}
so as I know ,run setInterval multiple times, and I believe while will count more
You ask if it is possible to
run setInterval more than once per millisecond in nodejs
As you note in your question, this is not possible with setInterval, since there is always a minimum delay of at least 1 ms in node.js. In browsers, there is often a minimum delay of at least 10 ms.
However, what you want to achieve—to repeatedly run CPU-intensive code without unnecessary delay—is possible in other ways.
As noted in the answer by The Reason, setImmediate is a good option available in node.js. As setImmediate has limited browser support, and is unlikely to be widely supported in the future, there is another approach that also works in browsers.
While browsers enforce a minimum delay for setInterval and setTimeout, the delay for setTimeout is enforced from when the timer is set, not when it is run. If we use setTimeout repeatedly to call CPU-intensive code, we can make sure that a timer is always set 10–15 ms in advance (if the code takes at least 10–15 ms to run), thus reducing the actual delay to 0 ms.
The demo snippet below borrows code from this answer to demonstrate how the use of timers set in advance may make the delay smaller than what is enforced. In the browsers I tested, this usually results in a 0 ms delay.
// First: repeat runCPUForAtLeast50ms() 10 times
// with standard repeated setTimeouts and enforced delays
testTimeout(10, function(){
// Then: repeat runCPUForAtLeast50ms() 10 times
// using a repeated set of queued setTimeouts
// circumventing the enforced delays
testTimeout(10, false, true);
});
function testTimeout(repetitions, next, multiple) {
var delays = [];
var lastCheck;
var extraTimers;
function runner() {
if(lastCheck){
delays.push((+new Date) - lastCheck);
}
if(repetitions > 0) {
//process chunk
runCPUForAtLeast50ms();
//set new timer
setTimeout(runner);
} else if(repetitions === 0) {
//report result to console
console.log((multiple?
'Repeated multiple timers delays: ' :
'Repeated single timer delays: ') + delays.join(', '));
//invoke next() function if provided
next && next();
}
repetitions--;
lastCheck = +new Date;
}
setTimeout(runner);
if(multiple){
// make sure that there are always a fixed
// number of timers queued by setting extra timers
// at start
extraTimers = 10;
while(extraTimers--)
setTimeout(runner);
}
}
function runCPUForAtLeast50ms() {
var d = (+new Date) + 50;
while(+new Date < d);
}
I think you can solve your problem using async module... a way could be:
async.parallel([
(callback) => {
// do normal stuff
},
(callback) => {
// do your loop
}
], (err, results) => {
// ...
});
But take into account this note from the official documentation...
Note: parallel is about kicking-off I/O tasks in parallel, not about
parallel execution of code. If your tasks do not use any timers or
perform any I/O, they will actually be executed in series. Any
synchronous setup sections for each task will happen one after the
other. JavaScript remains single-threaded.
In short answer, you can't. There are some limitation of Javascript/Node as it is a single thread application. That's why you have async interrupts.
The long answer:
From the computer architecture's perspective, modern CPU and Kernel scheduling is not deterministic. If you want such fine grain control, I would suggest you look at MCU and embedded solutions that does not have a kernel scheduler. Because, your OS have many other processes and Kernel processes that takes up CPU time, so kernel scheduler have to keep scheduling different processes to be run on the CPU and meet many different demands.
Even with the set 1ms, when you try to measure, it is probably not 1ms (exact time depends on OS, hardware and amount of processes running on your computer).
Now, if you want to use all CPU resources, not possible.
But if you want to utilize as much as resources as possible, you can explore current programming pattern. For example, you can schedule 1 million threads (you machine probably won't be able to handle it), or some crazy large amount of processes and let your scheduler to be constantly putting process on your CPU, so there is no idle time and max out CPU utilization.
Alternatively, you can run CPU Stress tests, and those are designed to simply max out your CPU and keep it burning to high temperature -- make sure you have the cooling solution in place.

NodeJs setInterval without extending process life time

I simplified it to better understand what I need: The task that I have to do is, that we have a long unknown nodejs process (with a lot of queued async functions where we never know when they are finished or something like that) and we want to have an update process, that we store current process state in database. For that we have a start up (it stores "start") and a end process that is on top of process.on('beforeExit', function () { ... });. Now we have to handle the "still in running" process that is requested by our customer. For that we want to update the state every ten minutes to running with timestamp (this function already exists and is called state.setRunningState()
Now I have the problem how can I trigger that function every ten minutes. For that I was going the approach to trigger on each event of the working process this function and compares if it is older then 10 minutes ago. Problem is: Some times there are much more time without any event. So second option is setInterval() and here is what my question is about: If I use setInterval my nodejs process will never reach an end, so the process will run endless until Interval is cleared. But I also do never know when I should call clearInterval()
So the Question is: Is there a way to create such a timeout without extending the life time of the nodejs process. If everything is done it should end and ignore the rest of the interval.
Contrary to some of the comments here, this is not a strange requirement to have something executed periodically while the process is running without making the process run infinitely which would make it quite pointless.
There is a built-in mechanism for that. If you don't want your interval (or timeout) to stop the process from exiting then you need to use the .unref() method.
Instead of:
setInterval(() => {
console.log('Interval');
}, 1000);
use:
setInterval(() => {
console.log('Interval');
}, 1000).unref();
and your interval will not stop the process from exiting if there are no other events pending.
Try running this example:
setInterval(() => {
console.log('Interval');
}, 1000).unref();
setTimeout(() => {
console.log('Timeout 1');
}, 3000);
setTimeout(() => {
console.log('Timeout 2');
}, 5000);
See the docs:
https://nodejs.org/api/timers.html#timers_timeout_unref
Let me see if I get this straight.
1- You want to trigger an event every x mins unless if the existing process has ended?
2- You say that node would not quit the process as long as there is a running set interval.
3- you say that since your process runs " lot of queued async functions" you cannot know when the process should end
I think the simplest solution would be to just set another interval to run at a higher frequency and to clear the interval if all functions have returned. Otherwise you might be interested in reading about webworkers
https://www.npmjs.com/package/webworker-threads

Test Javascript Function's Blocking Behavior

In Javascript, I have two versions of a recursive function, one that runs synchronously and one that uses simple scheduling to run asynchronously. Given certain inputs, in both cases the function is expected to have an infinite execution path. I need to develop tests for these functions, specifically a test to check that the asynchronous version does not block the main thread.
I already have tests that check the output callback behavior of these functions in non-returning cases, I am only concerned about testing the blocking behavior. I can limit how long the function runs to some long but finite amount of time for testing purposes as well. I am currently using QUnit but can switch to another testing framework.
How can I test that a non-returning, asynchronous function does not block?
Edit, For Clarification
This would be a bare bones example of the function I am working with:
function a()
{
console.log("invoked");
setTimeout(a, 1000);
}
a();
I am intentionally misusing some threading terms in my description because I felt they most clearly expressed the problem. By not blocking the main thread, I mean that invoking the function does not prevent the scheduling and execution of other logic. I expect the function itself will be executed on the main thread but I consider the function running as long as it is scheduled for execution in the future.
Unit Test are based on single-responsability-principle and isolation (separate the subject under test from it's dependencies).
In this case, you expect your function to run asynchronously but this behaviour is not done by your function, is done by the "setTimeout" function, so I think you must isolate your function from "setTimeout" since it's a dependency you don't want to test, the browser guarantees you it will work.
Then, as we trust "setTimeout" will do the asyncrhonous logic, we can only test our function calls to "setTimeout" and we can do this replacing "window.setTimeout" with another function while we must always restore it after the test is complete.
function replaceSetTimeout() {
var originalSetTimeout = window.setTimeout;
var callCount = 0;
window.setTimeout = function() {
callCount++;
};
window.setTimeout.restore = function() {
window.setTimeout = originalSetTimeout;
};
window.setTimeout.getCallCount = function() {
return callCount;
};
}
replaceSetTimeout();
asyncFunction();
assert(setTimeout.getCallCount() === 1);
setTimeout.restore();
I recommend you to use sinon.js as it provides many tools like spies who are functions than will inform you about how many times and with what arguments where called.
var originalSetTimeout = window.setTimeout;
window.setTimeout = sinon.spy();
asyncFunction();
// check called only once
assert(setTimeout.calledOnce);
// check the first argument was asyncFunction
assert(setTimeout.calledWith(asyncFunction));
Sinon also provides fake timers who does the setTimeout substitution but with so much more features, like the .tick(x) method who will simulate "x" milliseconds but in this case I think it doesn't help you.
Update to answer question edit:
1 - Your function executes infinitely so you cannot test it without interrupting it's execution, so you must overwrite "setTimeout" somewhere.
2 - You want your function to execute recursively allowing other code to be executed between iterations? great! but understand than your function can not do this your function only can call setTimeout or setInterval and hope this function work as expected. You should test what your function does.
3 - You want to test from Javascript (a sandboxed environment) than another Javascript code uses and releases the only one execution thread (the same you are using to test). Do you really think this is an easy test?
4 - but the most important one - I don't like white box because it couples the test with the dependency, if you change your dependency or how it's called in the future you will have to change the test. This problem doesn't exist with DOM function, DOM functions will keep the same interface for years, and for now, you have no other way to do what you want than calling one of those two functions, so I don't think in this case "white box testing" is a bad idea.
I told you this because I had the same problem testing a Promise pattern implementation than had to be always asynchronous, even if the promise is already fulfilled, and I've tested it using test-engine asynchronous-test way (using callbacks and stuff) and it was a mess, test failing randomly, so much slow test execution. Then I asked a TDD expert how can test be so hard and he answered than I was not following Single Responsability Principle since I was trying to test my promise implementation AND the setTimeout behaviour.
If you think about it from a Behaviour Driven Testing perspective then 'Does my function block?' is not a useful question. It will definitely block, a better question might be 'does it return in no more than 50ms'.
You could do this with something like :
test( "speed test", function() {
var start = new Date();
a();
ok(new Date() - start < 50, "Passed!" );
});
The issue with this is that if someone does do something silly that makes your function block indefinitely the test won't fail, it will hang.
Because JavaScript is single threaded there is no way around this. If I come along and change your function to :
function a() {
while(true) {
console.log("invoked")
}
}
The test will hang.
You can make breaking things this way harder by refactoring things a little. There are 2 separate things being done. Your chunk of work and the scheduling. Separate these and you'll end up with something like the following functions :
function a() {
// doWork
var stopRunning = true;
return stopRunning;
}
function doAsync(workFunc, scheduleFunc, timeout) {
if (!workFunc()) {
scheduleFunc(doAsync, [workFunc, scheduleFunc, timeout], timeout);
}
}
function schedule(func, args, timeout) {
setTimeout(function() {func.apply(window, args);}, timeout);
}
Now you're free to test everything in isolation. You can supply a mock workFunc and scheduleFunc to a test for doAsync to verify it behaves as expected and you can test your function a() without worrying about how it is scheduled.
It's still possible for a dunce programmer to put an infinite loop into the function a(), but because they don't have to consider how to run further units of work it should be less likely.
To test or prove an infinitely executing execution path will never block is next to impossible, so you have to split your problem up into parts.
Your path is basically foo(foo(foo(foo(...etc...)))), nevermind that SetTimeout actually removes recursion. So all you have to do is test or prove that your foo does not block (I tell you now that testing will be "a bit" easier than proving, more below)
So, does function foo block?
Talking a bit maths, if you want to know whether f(f(...f(x)...)) always has a value, you actually only have to prove that f(x) always has a value for any x that f can return. It does not matter how many recursions you have, if you can make sure their return values are fine.
What that means for your foo is that you only have to prove that foo does not block for any possible input value. Keep in mind that in this case, all global variables and closures are input values too. This means you have to sanity-check every single value you are using on every call.
To test, of course you will have to replace SetTimeout, but that is trivial, and if you replace it with an empty function (function(){}) it is easy to prove that this function does not block or otherwise alter your execution. You will then
Making things easier
Taking in what I wrote above, this also means that you would have to make sure no global function or variable that you are ever using will ever be changed to a point that your function breaks to a point it breaks. This actually is quite hard, but you can still make things easier for you by making sure you always use the same functions and values and that other functions can not touch them by using closures.
function foo(n, setTimeout)
{
var x = global_var;
// sanity check n here
function f()
{
setTimeout(f, n)
}
return f();
}
This way, you only have to test those values on the first execution. It's nice to be able to assume Math.Pi is actually Pi and not a string value containing "noodles". Really nice.
Do not use global mutable objects
Call those you can not circumvent using setTimeout to ensure they can not block
If you need return values, things will get really tricky, but possible, consider this:
function() {
var x = 0;
setTimeout(function(){x = insecure();}, 1);
}
All you have to do is
Use x next iteration
Sanity check value of x first!
Does SetTimeout block?
Of course this depends on whether setTimeout blocks. This is quite hard to prove, but a bit easier to test. You can't actually prove it since it's implementation is up to the interpreter.
Personally I would assume that setTimeout behaves like an empty function when it's return value is discarded.
Performing this asynchronous testing is actually possible in QUnit but is handled better in another JavaScript testing framework, Jasmine JS. I'll provide examples in both.
In QUnit you need to first call the stop() function to signal that the test is expected to run asynchronously, you should then call setTimeout with a function that includes your expectations as well as a call to the start() function to complete the block. Here's an example:
test( "a test", function() {
stop();
asyncOp();
setTimeout(function() {
equals( asyncOp.result, "someExpectedValue" );
start();
}, 150 );
});
Edit: Apparently there's also a whole asyncTest construct that you can use that simplifies this process. Take a look: http://api.qunitjs.com/asyncTest/
In Jasmine (http://pivotal.github.com/jasmine/), a Behavior Driven Development (BDD) testing framework, there are built-in methods for writing asynchronous tests. Here's an example of an asynchronous test in Jasmine:
describe('Some module', function() {
it('should run asynchronously', function() {
var isDone = false;
runs(function() {
// The first call to runs should trigger some async operation
// that has a side-effect that can be tested for. In this case,
// lets say that the doSomethingAsyncWithCallback function
// does something asynchronously and then calls the passed callback
doSomethingAsyncWithCallback(function() { isDone = true; });
});
waitsFor(function() {
// The call to waits for is a polling function that will get called
// periodically until either a condition is met (the function should return
// a boolean testing for this condition) or the timeout expires.
// The optional text is what error to display if the test fails.
return isDone === true;
}, "Should set isDone to true", 500);
runs(function() {
// The second call to runs should contain any assertions you need to make
// after the async call is complete.
expect(isDone).toBe(true);
});
});
});
Edit: Also, Jasmine has several built-in methods of faking out the setTimeout and setInterval functions of the browser without hosing any other tests in your suite that may depend on that. I would take a look at using those rather than manually overriding the setTimeout/setInterval functions.
Basically, JavaScript is single-threaded, so it will block the main thread. But :
I assume you're using setTimesout to schedule your function, so it won't be noticeable to the user if calls to that function don't take too much time (say, less than 200 or 300ms).
If you're doing DOM manipulation during that function (including Canvas or WebGL), then you're screwed. But if not, you can look into Web Workers, which can spawn separate threads that are guaranteed not to block the UI.
But anyway, JavaScript and the main loop, that's a tricky issue that's been bugging me a lot these past months, so you're not alone!
As soon as your function returns (after having set the timeout for it's next run), javascript will look at the next thing that requires running and run that.
As far as I can tell, the 'main thread' in javascript is just a loop that is responding to events (such as onload for a script tag, which runs the contents of that tag).
Based on the above two conditions, the calling thread is always going to run to completion despite any setTimeouts, and those timeouts will begin after the calling thread has nothing left to run.
The way I tested this was to run the following function right after the call to a()
function looper(name,duration) {
var start = (new Date()).getTime();
var elapsed = 0;
while (elapsed < duration) {
elapsed = (new Date()).getTime() - start;
console.log(name + ": " + elapsed);
}
}
Duration should be set to some period of time longer than the setTimeout duration in a(). The expected output would be the output of 'looper', followed by the output of repeated calls to a().
The next thing to test would be whether other script tags are able to run while a() and its child calls are executing.
You can do this like so:
<script>
a();
</script>
<script>
looper('delay',500); // ie; less than the 1000 timeout in a();
</script>
<script>
console.log('OK');
</script>
You would expect 'OK' to appear in the log despite the fact that a() and its children are still executing. You can also test variations of this, such as window.onload(), etc.
Finally, you'd want to ensure that other timer events work fine as well. Simply delaying 2 calls by half a second and checking that they interleave should show that works fine:
function b()
{
console.log("invoked b")
setTimeout(b, 1000);
}
a();
looper('wait',500);
b();
Should produce output like
invoked
invoked b
invoked
invoked b
invoked
invoked b
Hope that's what you were looking for!
EDIT in case you need some technical details on how to do it in Qunit:
If Qunit can't capture console.log output (i'm not sure), just push those strings into an array or a string and check that after it's run. You could override console.log in the test module() setup and restore it at teardown. I'm not sure how Qunit works but 'this' might have to be removed and globals used to store the old_console_log and test_output
// in the setup
this.old_console_log = console.log;
this.test_output = [];
var self = this;
console.log = function(text) { self.test_output.push(text); }
// in the teardown
console.log = this.old_console_log;
Finally, you can utilize stop() and start() so that Qunit knows to wait for all the events in the test to finish running.
stop();
kickoff_async_test();
setTimeout(function(){
// assertions
start();
},<expected duration of run>);
Based on all the answers, I came up with this solution that works for my case:
testAsync("Doesn't hang", function(){
expect(1);
var ranToLong = false;
var last = new Date();
var sched = setInterval(function(){
var now = new Date();
ranToLong = ranToLong || (now - last) >= 50;
last = now;
}, 0);
// In this case, asyncRecursiveFunction runs for a long time and
// returns a single value in callback
asyncRecursiveFunction(function callback(v){
clearInterval(sched);
var now = new Date();
ranToLong = ranToLong || (now - last) >= 50;
assert.equal(ranToLong, false);
start();
});
});
It tests that 'asyncRecursiveFunction' does not hang while processing by looking at the time between another scheduled function calls.
This is really ugly and not be applicable to every case but it seems to work for me because I can restrict my function to some large set of async recursive calls so it runs for a long but not infinite time. As I mentioned in the question, I am happy proving that such cases do not block.
BTW, the actual code in question is found in gen.js. The main problem was an async reduce generator. It correctly returned a value asynchronously, but in previous versions would stall because of synchronous internal implementation.

Checking if a JavaScript setTimeout has fired

I'd like to be able to dispatch a bunch of work via JavaScript to be done in the browser in such a way that the browser stays responsive throughout.
The approach I'm trying to take is to chunk up the work, passing each chunk to a function that is then queued with a setTimeout(func, 0) call.
I need to know when all the work is done, so I'm storing the returned timer ID in a map (id -> true|false). This mapping is set to false in the next block of code after I have the timer ID, and the queued function sets the mapping to true when it completes... except, of course, the queued function doesn't know its timer ID.
Maybe there's a better/easier way... or some advice on how I can manipulate my map as I need to?
I would queue the work in an array, use one timeout to process the queue and call a callback once the queue is empty. Something like:
var work = [...];
var run = function(work, callback) {
setTimeout(function() {
if(work.length > 0) {
process(work.shift());
setTimeout(arguments.callee, 25);
}
else {
callback();
}
}, 25);
};
run(work, function() {
alert('Work is done!');
});
As JavaScript in browsers is single threaded there is no real advantage to run multiple timeouts (at least I think this is what you are doing). It may even slow down the browser.
I'd like to add that although javascript is single threaded you can still have multiple ajax calls going at once. I recently had a site that needed to do potentially hundreds of ajax calls and the browser just couldn't handle it. I created a queue that used setTimeOut to run 5 calls at once. When one of the ajax calls returned it fired a callback (which is handled by a single thread) and then made the next call on the stack.
Imagine you're a manager that can only talk to one person at a time, you give 5 employees assignments, then wait for their responses, which may come in any order. Once the first employee comes back and gives you the information, you give them a new assignment and wait for the next employee (or perhaps even the same employee) to come back. So although you're "single threaded" 5 things are going on at once.
There is an example right in the HTML Standard, how it is best to handle it:
To run tasks of several milliseconds back to back without any delay,
while still yielding back to the browser to avoid starving the user
interface (and to avoid the browser killing the script for hogging the
CPU), simply queue the next timer before performing work:
function doExpensiveWork() {
var done = false;
// ...
// this part of the function takes up to five milliseconds
// set done to true if we're done
// ...
return done;
}
function rescheduleWork() {
var handle = setTimeout(rescheduleWork, 0); // preschedule next iteration
if (doExpensiveWork())
clearTimeout(handle); // clear the timeout if we don't need it
}
function scheduleWork() {
setTimeout(rescheduleWork, 0);
}
scheduleWork(); // queues a task to do lots of work
The moment of finishing the work is pretty clear, when clearTimeout is called.

Is there any way to call a function periodically in JavaScript?

Is there any way to call a function periodically in JavaScript?
The setInterval() method, repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. It returns an interval ID which uniquely identifies the interval, so you can remove it later by calling clearInterval().
var intervalId = setInterval(function() {
alert("Interval reached every 5s")
}, 5000);
// You can clear a periodic function by uncommenting:
// clearInterval(intervalId);
See more # setInterval() # MDN Web Docs
Please note that setInterval() is often not the best solution for periodic execution - It really depends on what javascript you're actually calling periodically.
eg. If you use setInterval() with a period of 1000ms and in the periodic function you make an ajax call that occasionally takes 2 seconds to return you will be making another ajax call before the first response gets back. This is usually undesirable.
Many libraries have periodic methods that protect against the pitfalls of using setInterval naively such as the Prototype example given by Nelson.
To achieve more robust periodic execution with a function that has a jQuery ajax call in it, consider something like this:
function myPeriodicMethod() {
$.ajax({
url: ...,
success: function(data) {
...
},
complete: function() {
// schedule the next request *only* when the current one is complete:
setTimeout(myPeriodicMethod, 1000);
}
});
}
// schedule the first invocation:
setTimeout(myPeriodicMethod, 1000);
Another approach is to use setTimeout but track elapsed time in a variable and then set the timeout delay on each invocation dynamically to execute a function as close to the desired interval as possible but never faster than you can get responses back.
Everyone has a setTimeout/setInterval solution already. I think that it is important to note that you can pass functions to setInterval, not just strings. Its actually probably a little "safer" to pass real functions instead of strings that will be "evaled" to those functions.
// example 1
function test() {
alert('called');
}
var interval = setInterval(test, 10000);
Or:
// example 2
var counter = 0;
var interval = setInterval(function() { alert("#"+counter++); }, 5000);
Old question but..
I also needed a periodical task runner and wrote TaskTimer. This is also useful when you need to run multiple tasks on different intervals.
// Timer with 1000ms (1 second) base interval resolution.
const timer = new TaskTimer(1000);
// Add task(s) based on tick intervals.
timer.add({
id: 'job1', // unique id of the task
tickInterval: 5, // run every 5 ticks (5 x interval = 5000 ms)
totalRuns: 10, // run 10 times only. (set to 0 for unlimited times)
callback(task) {
// code to be executed on each run
console.log(task.id + ' task has run ' + task.currentRuns + ' times.');
}
});
// Start the timer
timer.start();
TaskTimer works both in browser and Node. See documentation for all features.
You will want to have a look at setInterval() and setTimeout().
Here is a decent tutorial article.
yes - take a look at setInterval and setTimeout for executing code at certain times. setInterval would be the one to use to execute code periodically.
See a demo and answer here for usage
Since you want the function to be executed periodically, use setInterval
function test() {
alert('called!');
}
var id = setInterval('test();', 10000); //call test every 10 seconds.
function stop() { // call this to stop your interval.
clearInterval(id);
}
The native way is indeed setInterval()/clearInterval(), but if you are already using the Prototype library you can take advantage of PeriodicalExecutor:
new PeriodicalUpdator(myEvent, seconds);
This prevents overlapping calls. From http://www.prototypejs.org/api/periodicalExecuter:
"it shields you against multiple parallel executions of the callback function, should it take longer than the given interval to execute (it maintains an internal “running” flag, which is shielded against exceptions in the callback function). This is especially useful if you use one to interact with the user at given intervals (e.g. use a prompt or confirm call): this will avoid multiple message boxes all waiting to be actioned."

Categories

Resources