Pipelining setTimeout in node.js - javascript

I am writing a node.js console application. I have two setTimeout functions as follows.
setTimeout(function(){
process.stdout.write('\n\nJokes Apart !!!\n\n');
}, 2000);
setTimeout(function(){
process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 1000);
What I actually intend is, the first message should come after 2 seconds. After that, the second message should appear after 1 second. But what's happening is, the second message appears after 1 second and then the first message appears. Both the functions are being called at once as they are asynchronous. Is there any way to pipeline them?

setTimout() is not blocking in Javascript. So, what you did is you scheduled two timers to run in the future. One runs 1 second from now. The other runs two seconds from now. Thus, you get the behavior you observed.
You can either schedule the first one to run 2 seconds from now and then for one to go 1 second after that, you schedule it for 3 seconds from now.
setTimeout(function(){
process.stdout.write('\n\nJokes Apart !!!\n\n');
}, 2000);
// schedule this one to be 3 seconds from now, which will be 1 second after the prior one
// since that one fired in 2 seconds
setTimeout(function(){
process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 3000);
Or, you can schedule the first one to run 2 seconds from now and then in that callback, you then schedule the next one to run 1 second from when the first one fires.
setTimeout(function(){
process.stdout.write('\n\nJokes Apart !!!\n\n');
// when the first timer fires, set a new timer to run the second
// part one second from when the first one fired
setTimeout(function(){
process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 1000);
}, 2000);
This non-blocking characteristic is what gives Javascript it's asynchronous behavior. When you call the first setTimeout(), the Javascript interpreter doesn't just stop and wait for the timer to fire. Instead, it schedules that timer to run sometime in the future and then it keeps on executing the rest of your Javascript. In your code, the next line of code is another setTimeout() so it immediately schedules that timer too. Since they were both scheduled at the same time, it makes sense that the one scheduled for 2 seconds from now comes after the one scheduled for 1 second from now.
Thus, you end up with two choices. You can either change the time on the second time to make it fire when you want it to fire (given that the code to schedule both timers is run at basically the same time) or you can change when you schedule the second timer until after the first timer has fired.

To understand what's happening, you should first understand the JS event loop and its non-blocking nature. You can read about it here: https://blog.risingstack.com/node-js-at-scale-understanding-node-js-event-loop/, or if you prefer video form, this is a great talk: https://youtu.be/8aGhZQkoFbQ
In a nutshell, the engine goes through the code - when it encounters the first setTimeout, it schedules it (for 2 seconds later), and keeps going. It then sees the second setTimeout and schedules it as well. When a second passes, the callback from the second setTimeout is triggered and executed, and only a second later, the callback from the first one is triggered. This is why you see them in that order.
Now to fixing it - all you need to do is just nest them:
setTimeout(function(){
process.stdout.write('\n\nJokes Apart !!!\n\n');
setTimeout(function(){
process.stdout.write('\n\nLet\'s play a game !!!\n\n');
}, 1000);
}, 2000);
This causes the second setTimeout to get scheduled only when the callback from the first one is run.

Related

Node.js - are setTimeout callbacks fired in the same order as registered?

I was wondering whether node.js guarantees the execution order of "expired" (ready to be executed) callbacks scheduled via setTimeout. The manual seems to claim that the Timers phase of the event loop has a FIFO queue of callbacks.
Taking this into account in the example below, I expected that node schedules the first callback and after 1 second the remaining two in the order as specified in the code. Now, when the first callback fires, the execution "stops" for 5 seconds which means that when the callback returns, the other two are ready to be executed as well.
However, when I run the example, the output seems to be first, third, second. Strangely, when the delay time of the second callback is modified to, e.g., 2001 instead of 2000, the order is as expected, i.e., first, second, third. Is this behavior by design?
const spawnSync = require('child_process').spawnSync;
function wait(delta){
spawnSync('sleep', [delta]);
}
setTimeout(() => {
console.log('first');
wait(5);
}, 2000);
wait(1);
setTimeout(() => {
console.log('second');
}, 2000);
setTimeout(() => {
console.log('third');
}, 4000);
After a closer inspection of the callback scheduling implementation in Node, it does indeed seem that the order of the second/third callbacks in the posted example is not really guaranteed.
The reason for this is how Node handles setTimeout callbacks in lib/timers.js. In short, these callbacks are stored in linked lists grouped by their corresponding delay time. Now, if one callback fires, Node determines its group, marks current time t_now and processes all callbacks within the group. For each one, it knows its registration time t_reg (when it was registered via setTimeout) and delay time delta. If t_now - t_reg >= delta, it invokes the callback. The thing is that t_now is evaluated only once for the entire group of callbacks corresponding to the same delay time.
To illustrate this, I compiled Node in debug mode (--debug option of ./configure script) and executed the example as:
NODE_DEBUG=timer node ./example.js
On my machine, I get the following:
TIMER 38963: no 2000 list was found in insert, creating a new one
TIMER 38963: no 4000 list was found in insert, creating a new one
TIMER 38963: timeout callback 2000
TIMER 38963: now: 2069
TIMER 38963: _idleStart = 64
first
TIMER 38963: _idleStart = 1074
TIMER 38963: 2000 list wait because diff is 995
TIMER 38963: timeout callback 4000
TIMER 38963: now: 7075
TIMER 38963: _idleStart = 1074
third
TIMER 38963: 4000 list empty
TIMER 38963: timeout callback 2000
TIMER 38963: now: 7076
TIMER 38963: _idleStart = 1074
second
TIMER 38963: 2000 list empty
Here, we see that the first and second callbacks were scheduled at times t1=64 and t2=1074, respectively. When the first callback is ready to fire at time T=2069, it takes more or less 5 seconds to execute it. Once this
execution finishes, Node continues within the same group of callbacks (i.e., callbacks associated with the same delay time) thus checking the second callback. However, it takes into account as current time not the time after the execution of the first callback but the time T when it started processing the callbacks (entered the listOnTimeout function in lib/timers.js). On my machine, since the second callback was registered at time 1074, 2069 - 1074 is less than the delay time of 2000 and thus the second callback is not executed but rescheduled instead for later with delay time of 995 (however, with respect to the current time, not with respect to T).
To be more specific, since the first callback fires, we know that T - t1 >= delta. However, the relationship between T - t2 and delta is not guaranteed. To illustrate this, if I remove the wait(1) call, I get:
TIMER 39048: no 2000 list was found in insert, creating a new one
TIMER 39048: no 4000 list was found in insert, creating a new one
TIMER 39048: timeout callback 2000
TIMER 39048: now: 2067
TIMER 39048: _idleStart = 66
first
TIMER 39048: _idleStart = 67
second
TIMER 39048: 2000 list empty
TIMER 39048: timeout callback 4000
TIMER 39048: now: 7080
TIMER 39048: _idleStart = 67
third
TIMER 39048: 4000 list empty
So now, the second callback is scheduled at t2=67, i.e., 2 units of time later than the first callback. Now when first fires at time T=2067, Node processes the entire group of callbacks associated with delay time of 2000 as mentioned above thus proceeding to the second callback - in this case, T-t2 is exactly equal to 2000 so that second is "luckily" fired as well. However, were the scheduling of the second callback delayed by mere 1 unit (due to for example some extraneous function call before invoking setTimeout), the third callback would fire sooner.
From the docs
The timeout interval that is set cannot be relied upon to execute after that exact number of milliseconds. This is because other executing code that blocks or holds onto the event loop will push the execution of the timeout back. The only guarantee is that the timeout will not execute sooner than the declared timeout interval.
I think your example is demonstrating all these points, moreso the one around the fact that timers can be pushed back. It would appear to me that the calls to spawnSync are delaying the timers just enough to cause the overlap - presumably if you reduced the delay of the wait call in the first setInterval or increase the timeout of the last setInterval you’d see a more consistent behaviour.

Why the unexpected result showing the results?

function init(n) {
console.log(n);
setInterval(init.bind(this, ++n), 1000);
}
// init(0); // Works bad
function init2(n) {
setInterval(function() {
console.log(n++);
}, 1000);
}
init2(0); // Works fine
The first is a recursive function with to a setInterval.
Why does the first function NOT work as "expected"? with "expected" I mean that every 1 second is shown n + 1
I have been told that it is because by calling itself, calls are multiplying more and more and overflowing memory.
This I have noticed, but I can not make the mental image of this, can someone explain it to me more detailed? My problem is that I thought that, when executing the function every 1 second, I assured myself that exactly that would happen, but no. Calls multiply and do not wait for 1000 ms.
My mental image of the flow is:
1 - Call init ()
2 - Show n and then add 1 to n
3 - With a setInterval, execute the init () function only if 1000 ms have
passed.
4- 1 second passed ..
5- We return to step 1
Call init() manually. The function starts an interval that triggers once every second.
A second later, the interval triggers the first time and calls init() which starts another interval.
Two seconds later (counting from the start) both intervals trigger and call init(). Both function calls start a new interval. There are now 4 intervals in total.
Three seconds later the 4 intervals trigger and each start a new interval. There are now 8 intervals in total.
and so on until you run out of resources.
In init2() this doesn't happen because the interval never calls the function again and therefore there's ever only one interval running.
The first snippet is fine if you use setTimeout instead:
function init(n) {
if (n > 10) return; // 10 is enough in the example code
console.log(n);
setTimeout(init.bind(this, ++n), 1000);
}
init(0); // Works good
See, in your original case each call of init() runs setInterval - in other words, sets up a different task repeated each 1 sec. But you clearly need a single interval (as in the second snippet) - just continued at each step.
The problem is that init.bind(this, ++n) returns a new function and that new function then returns a new function, and so on. There isn't just one init function running every second. So, there are new copies being created every second and they are, in turn, making more copies. There isn't just one init running by itself. The copies are getting "stacked" up.

How does the delay parameter of setTimout() work within a loop?

I have the following code that involves an IIFE (immediately invoking function expression) within a for loop. The IIFE function is clearly getting the right parameter as the printout is as expected. But I don't understand what the interval is doing. As far as I can tell the interval for the 1st iteration should be 1 sec, then 2 sec for the 2nd iteration, etc. etc.
for (var i = 1; i <= 5; i++) {
(function(i){
setTimeout(function timer(){
console.log(i);
}, i*1000);
})(i);
}
I see i printed out as 1..5 in 1 second intervals. This is confusing for me, as I was expecting the interval to increase with each iteration.
With the following code:
for (var i = 1; i <= 5; i++) {
(function(i){
setTimeout(function timer(){
console.log(i);
}, 1000);
})(i);
}
I see all the values for i printed at once after a 1 second interval.
What is happening within the setTimeout function that is making it work in the way observed?
The for loop runs to completion. It doesn't wait for the setTimeout() call to fire. So, when the for loop is running, it schedules setTimeout() calls for 1000, 2000, 3000, 4000, 5000 ms from now. Thus, you see them all fire one second apart.
What is happening within the setTimeout function that is making it
work in the way observed?
setTimeout() is a non-blocking, asynchronous operation. It is scheduled to run in the future, but the other code around it continues to run. Then, sometime in the future the timer fires and the callback is called.
So, your code is essentially this:
setTimeout(fn, 1000);
setTimeout(fn, 2000);
setTimeout(fn, 3000);
setTimeout(fn, 4000);
setTimeout(fn, 5000);
It runs all the setTimeout() calls one after the other in a non-blocking fashion. Each setTimeout() function call just registers a callback and a time with the underlying system and then the next line of code continues to execute. Then, sometime later when the right amount of time has passed, the callback gets called. So, hopefully you can see that all the timers are all scheduled to measure their time starting from now. Thus, you see them fire each 1 second apart.
If you want an analogy for an asynchronous operation, imagine you walk around your house and you set five alarm clocks to start ringing at a time in the future. You set one to ring an hour from now, one for two hours from now, one for three hours from now, etc... Then, you go about your other business, make lunch, clean the kitchen, mow the grass, etc... and one hour from when you set all the clocks, the first alarm starts ringing. One hour after that, the next one starting ringing, etc... You get to keep doing things before and after they ring. You don't have to sit and wait for a clock to ring before doing anything else. That's what Javascript asynchronous timer operations are like. You set them and then keep running other code and they fire at their scheduled time in the future.
Try this :
function recursiveTimeout(i) {
setTimeout(function timer(){
console.log(i);
if(i<5) {
recursiveTimeout(i+1);
}
}, 1000 * i);
}
recursiveTimeout(1);
That way the next setTimeout is depending of the end of parent timer.

Javascript - run time priority and queue

if i do:
setTimeout(function(){ alert('antani'); },400);
setTimeout(function(){ alert('supercazzola'); },400);
why does this script generates queue between these two timeouts?
Shouldn't they alerted in same moment?
as i can see testing it out, first, the first alert is executed, then the second.
Background
JavaScript has only the one thread in which the interpreter is running. This means that events are never processed at the same time. When you set a timeout you actually subscribe to some internal event of the browser that fires each time browser is in the idle mode (when not busy with rendering, parsing or executing some script, etc.). The handlers of this event as well as time they were scheduled are posted to the queue according to the order setTimeout appeared in the script. Each time this internal event is fired, the browser checks each handler and decides whether to execute and remove it from the queue or to skip it.
Same Time
When you schedule the tasks one after another with the same estimation time
setTimeout(function(){ $('.element').hide(); },400);
setTimeout(function(){ $('.element').show(); },400);
the .element will be first hidden and then shown. Note that it does not mean that the browser will render the change to .element after it's hidden. Most browsers will only render after the script has finished executing.
Different Time
When you schedule tasks with different estimation times:
setTimeout(function(){ $('.element').hide(); },401);
setTimeout(function(){ $('.element').show(); },400);
the result may be unpredictable. The following cases may occur:
more or equal to 400 and less than 401 milliseconds have passed and browser is starting to process event handlers. In this case .element will first be shown and then hidden. Note that there may be other setTimeouts scheduled to be executed after 400 milliseconds and they will run prior to the hide .element.
browser was busy for 401 milliseconds or more before it first starts to process event handlers. In this case most likely (depending on browser implementation) the .element will first be hidden and then shown, despite the fact that according to estimation time it should be vice versa!
Regarding your question: is it the same to set timeouts with the same time or some positive delta the answer is NO. It is not the same, when you set timeouts with delta there is always a possibility that another event or timeout will be processed between them.
Please read: http://ejohn.org/blog/how-javascript-timers-work/
Here's a similar example:
function a(){
var num = 5;
console.log( ++num );
setTimeout( a, 100 );
};
setTimeout(a,2000);
In chronological order:
you are defining function a without calling it
you are scheduling a to be invoked after two seconds: setTimeout(a,2000)
it is called
when it is called, it schedules itself for invocation after 100 milliseconds
Your code basically sleeps for 2 seconds and then executes a with 100 millisecond pauses[*].
However judging by your context you are asking what is the priority in the following situation:
setTimeout(a, 2000);
setTimeout(b, 100);
Well, most likely b will be called first (assuming there is no unpredictable pause between first and second line, e.g. due to overall OS performance problem).
If you use the same timeouts:
setTimeout(a, 100);
setTimeout(b, 100);
a will most likely be called first. However I don't think this is guaranteed and depends on the JS engine (whether it uses a strict FIFO list for upcoming events, what is the internal clock resolution, etc.)

setTimeout or setInterval?

As far as I can tell, these two pieces of javascript behave the same way:
Option A:
function myTimeoutFunction()
{
doStuff();
setTimeout(myTimeoutFunction, 1000);
}
myTimeoutFunction();
Option B:
function myTimeoutFunction()
{
doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);
Is there any difference between using setTimeout and setInterval?
They essentially try to do the same thing, but the setInterval approach will be more accurate than the setTimeout approach, since setTimeout waits 1000ms, runs the function and then sets another timeout. So the wait period is actually a bit more than 1000ms (or a lot more if your function takes a long time to execute).
Although one might think that setInterval will execute exactly every 1000ms, it is important to note that setInterval will also delay, since JavaScript isn't a multi-threaded language, which means that - if there are other parts of the script running - the interval will have to wait for that to finish.
In this Fiddle, you can clearly see that the timeout will fall behind, while the interval is almost all the time at almost 1 call/second (which the script is trying to do). If you change the speed variable at the top to something small like 20 (meaning it will try to run 50 times per second), the interval will never quite reach an average of 50 iterations per second.
The delay is almost always negligible, but if you're programming something really precise, you should go for a self-adjusting timer (which essentially is a timeout-based timer that constantly adjusts itself for the delay it's created)
Is there any difference?
Yes. A Timeout executes a certain amount of time after setTimeout() is called; an Interval executes a certain amount of time after the previous interval fired.
You will notice the difference if your doStuff() function takes a while to execute. For example, if we represent a call to setTimeout/setInterval with ., a firing of the timeout/interval with * and JavaScript code execution with [-----], the timelines look like:
Timeout:
. * . * . * . * .
[--] [--] [--] [--]
Interval:
. * * * * * *
[--] [--] [--] [--] [--] [--]
The next complication is if an interval fires whilst JavaScript is already busy doing something (such as handling a previous interval). In this case, the interval is remembered, and happens as soon as the previous handler finishes and returns control to the browser. So for example for a doStuff() process that is sometimes short ([-]) and sometimes long ([-----]):
. * * • * • * *
[-] [-----][-][-----][-][-] [-]
• represents an interval firing that couldn't execute its code straight away, and was made pending instead.
So intervals try to ‘catch up’ to get back on schedule. But, they don't queue one on top of each other: there can only ever be one execution pending per interval. (If they all queued up, the browser would be left with an ever-expanding list of outstanding executions!)
. * • • x • • x
[------][------][------][------]
x represents an interval firing that couldn't execute or be made pending, so instead was discarded.
If your doStuff() function habitually takes longer to execute than the interval that is set for it, the browser will eat 100% CPU trying to service it, and may become less responsive.
Which do you use and why?
Chained-Timeout gives a guaranteed slot of free time to the browser; Interval tries to ensure the function it is running executes as close as possible to its scheduled times, at the expense of browser UI availability.
I would consider an interval for one-off animations I wanted to be as smooth as possible, whilst chained timeouts are more polite for ongoing animations that would take place all the time whilst the page is loaded. For less demanding uses (such as a trivial updater firing every 30 seconds or something), you can safely use either.
In terms of browser compatibility, setTimeout predates setInterval, but all browsers you will meet today support both. The last straggler for many years was IE Mobile in WinMo <6.5, but hopefully that too is now behind us.
setInterval()
setInterval() is a time interval based code execution method that has the native ability to repeatedly run a specified script when the interval is reached. It should not be nested into its callback function by the script author to make it loop, since it loops by default. It will keep firing at the interval unless you call clearInterval().
If you want to loop code for animations or on a clock tick, then use setInterval().
function doStuff() {
alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);
setTimeout()
setTimeout() is a time based code execution method that will execute a script only one time when the interval is reached. It will not repeat again unless you gear it to loop the script by nesting the setTimeout() object inside of the function it calls to run. If geared to loop, it will keep firing at the interval unless you call clearTimeout().
function doStuff() {
alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);
If you want something to happen one time after a specified period of time, then use setTimeout(). That is because it only executes one time when the specified interval is reached.
The setInterval makes it easier to cancel future execution of your code. If you use setTimeout, you must keep track of the timer id in case you wish to cancel it later on.
var timerId = null;
function myTimeoutFunction()
{
doStuff();
timerId = setTimeout(myTimeoutFunction, 1000);
}
myTimeoutFunction();
// later on...
clearTimeout(timerId);
versus
function myTimeoutFunction()
{
doStuff();
}
myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);
// later on...
clearInterval(timerId);
I find the setTimeout method easier to use if you want to cancel the timeout:
function myTimeoutFunction() {
doStuff();
if (stillrunning) {
setTimeout(myTimeoutFunction, 1000);
}
}
myTimeoutFunction();
Also, if something would go wrong in the function it will just stop repeating at the first time error, instead of repeating the error every second.
The very difference is in their purposes.
setInterval()
-> executes a function, over and over again, at specified time intervals
setTimeout()
-> executes a function, once, after waiting a specified number of milliseconds
It's as simple as that
More elaborate details here http://javascript.info/tutorial/settimeout-setinterval
When you run some function inside setInterval, which works more time than timeout-> the browser will be stuck.
- E.g., doStuff() takes 1500 sec. to be execute and you do: setInterval(doStuff, 1000);
1) Browser run doStuff() which takes 1.5 sec. to be executed;
2) After ~1 second it tries to run doStuff() again. But previous doStuff() is still executed-> so browser adds this run to the queue (to run after first is done).
3,4,..) The same adding to the queue of execution for next iterations, but doStuff() from previous are still in progress...
As the result- the browser is stuck.
To prevent this behavior, the best way is to run setTimeout inside setTimeout to emulate setInterval.
To correct timeouts between setTimeout calls, you can use self-correcting alternative to JavaScript's setInterval technique.
Your code will have different execution intevals, and in some projects, such as online games it's not acceptable. First, what should you do, to make your code work with same intevals, you should change "myTimeoutFunction" to this:
function myTimeoutFunction()
{
setTimeout(myTimeoutFunction, 1000);
doStuff();
}
myTimeoutFunction()
After this change, it will be equal to
function myTimeoutFunction()
{
doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);
But, you will still have not stable result, because JS is single-threaded. For now, if JS thread will be busy with something, it will not be able to execute your callback function, and execution will be postponed for 2-3 msec. Is you have 60 executions per second, and each time you have random 1-3 sec delay, it will be absolutely not acceptable (after one minute it will be around 7200 msec delay), and I can advice to use something like this:
function Timer(clb, timeout) {
this.clb = clb;
this.timeout = timeout;
this.stopTimeout = null;
this.precision = -1;
}
Timer.prototype.start = function() {
var me = this;
var now = new Date();
if(me.precision === -1) {
me.precision = now.getTime();
}
me.stopTimeout = setTimeout(function(){
me.start()
}, me.precision - now.getTime() + me.timeout);
me.precision += me.timeout;
me.clb();
};
Timer.prototype.stop = function() {
clearTimeout(this.stopTimeout);
this.precision = -1;
};
function myTimeoutFunction()
{
doStuff();
}
var timer = new Timer(myTimeoutFunction, 1000);
timer.start();
This code will guarantee stable execution period. Even thread will be busy, and your code will be executed after 1005 mseconds, next time it will have timeout for 995 msec, and result will be stable.
I use setTimeout.
Apparently the difference is setTimeout calls the method once, setInterval calls it repeatdly.
Here is a good article explaining the difference: Tutorial: JavaScript timers with setTimeout and setInterval
I've made simple test of setInterval(func, milisec), because I was curious what happens when function time consumption is greater than interval duration.
setInterval will generally schedule next iteration just after the start of the previous iteration, unless the function is still ongoing. If so, setInterval will wait, till the function ends. As soon as it happens, the function is immediately fired again - there is no waiting for next iteration according to schedule (as it would be under conditions without time exceeded function). There is also no situation with parallel iterations running.
I've tested this on Chrome v23. I hope it is deterministic implementation across all modern browsers.
window.setInterval(function(start) {
console.log('fired: ' + (new Date().getTime() - start));
wait();
}, 1000, new Date().getTime());
Console output:
fired: 1000 + ~2500 ajax call -.
fired: 3522 <------------------'
fired: 6032
fired: 8540
fired: 11048
The wait function is just a thread blocking helper - synchronous ajax call which takes exactly 2500 milliseconds of processing at the server side:
function wait() {
$.ajax({
url: "...",
async: false
});
}
Both setInterval and setTimeout return a timer id that you can use to cancel the execution, that is, before the timeouts are triggered. To cancel you call either clearInterval or clearTimeout like this:
var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);
Also, the timeouts are automatically cancelled when you leave the page or close the browser window.
To look at it a bit differently: setInterval ensures that a code is run at every given interval (i.e. 1000ms, or how much you specify) while setTimeout sets the time that it 'waits until' it runs the code. And since it takes extra milliseconds to run the code, it adds up to 1000ms and thus, setTimeout runs again at inexact times (over 1000ms).
For example, timers/countdowns are not done with setTimeout, they are done with setInterval, to ensure it does not delay and the code runs at the exact given interval.
You can validate bobince answer by yourself when you run the following javascript or check this JSFiddle
<div id="timeout"></div>
<div id="interval"></div>
var timeout = 0;
var interval = 0;
function doTimeout(){
$('#timeout').html(timeout);
timeout++;
setTimeout(doTimeout, 1);
}
function doInterval(){
$('#interval').html(interval);
interval++;
}
$(function(){
doTimeout();
doInterval();
setInterval(doInterval, 1);
});
Well, setTimeout is better in one situation, as I have just learned. I always use setInterval, which i have left to run in the background for more than half an hour. When i switched back to that tab, the slideshow (on which the code was used) was changing very rapidly, instead of every 5 seconds that it should have. It does in fact happen again as i test it more and whether it's the browser's fault or not isn't important, because with setTimeout that situation is completely impossible.
The difference is obvious in console:
Just adding onto what has already been said but the setTimeout version of the code will also reach the Maximum call stack size which will stop it from functioning. Since there is no base case for the recursive function to stop at so you can't have it run forever.
If you set the interval in setInterval too short, it may fire before the previous call to the function has been completed. I ran into this problem with a recent browser (Firefox 78). It resulted in the garbage collection not being able to free memory fast enough and built up a huge memory leak.
Using setTimeout(function, 500); gave the garbage collection enough time to clean up and keep the memory stable over time.
Serg Hospodarets mentioned the problem in his answer and I fully agree with his remarks, but he didn't include the memory leak/garbage collection-problem. I experienced some freezing, too, but the memory usage ran up to 4 GB in no time for some minuscule task, which was the real bummer for me. Thus, I think this answer is still beneficial to others in my situation. I would have put it in a comment, but lack the reputation to do so. I hope you don't mind.
The reason why Option A and Option B seem like they work the same is mostly because the places of the setInterval and the setTimeout functions.
function myTimeoutFunction()
{
doStuff();
setTimeout(myTimeoutFunction, 1000);
}
myTimeoutFunction();
This one is a recursive function, and if doStuff is very complex, setTimeout has to keep track of all calls of the setTimout plus the current doStuff, which makes it become slower and s l o w e r.
function myTimeoutFunction()
{
doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);
On the other hand, the setInterval only has to keep track of the last setInterval and the current doStuff, making it staying at a constant speed.
So which one should you use?
From the above, you should probably be able to conclude that the better one is setInterval.
The important point to consider is the performance.
The only way to run a function periodically using setTimeout is to call it recursively with the target function, and when you check it, it appears that it works asynchronously put when you see the call stack you will find it keep growing by the time. In fact, it is sensible. Since Javascript does not support multi-threading, it is impossible to finish calling the parent function before finishing the child function, therefor, the stack will keep growing as long as there is recursive calling.
Whilst, with setInterval we don't need to call the target function recursively since it has a logic that runs it periodically as a loop. So, this keeps the call stack clean.
You can watch the call stack using developer's tools in your browser and you will notice the difference.
The difference will be clear when using small interval for a long period of time.
I think SetInterval and SetTimeout are different. SetInterval executes the block according to the time set while, SetTimeout executes the block of code once.
Try these set of codes after the timeout countdown seconds:
setInterval(function(e){
alert('Ugbana Kelvin');
}, 2000);
and then try
setTimeout(function(e){
alert('Ugbana Kelvin');
}, 2000);
You can see the differences for yourself.

Categories

Resources