Repeat actions after a given interval of time javascript. SetTimeOut and SetInterval which is better to use in JavaScript? Topic: SetTimeOut and SetInterval which is better to use in JavaScript
- From:
- Registered: 2014.07.08
- Posts: 3,896
- Likes: 497
Topic: SetTimeOut and SetInterval, which is better to use in JavaScript?
To repeatedly run the code at regular intervals, the function setInterval. Nevertheless, it has a number of disadvantages, mainly this is a different behavior in different browsers.
The first difference is the difference in the timer setting for the next run. Let's create a small test: we will measure the amount of time that has passed since the start of the previous run and from its end.
var d1 = new Date(), d2 = new Date(); setInterval(function() ( var d = new Date(); document.body.innerHTML += (d - d1) + " " + (d - d2) + "
"; // Put a label at the beginning of the function d1 = new Date(); while (new Date() - d1< 200); // ничего не делаем 200 миллисекунд
// И в конце функции
d2 = new Date();
}, 1000);
The output will be informative starting from the second line.
In Firefox, Opera, Safari and Chrome, the situation will be similar: the first number will be approximately equal to 1000, the second - 200 less. The difference will only be in the spread of values. The smallest spread in Chrome and Opera.
2 Reply by PunBB (edited by PunBB 2017.06.08 16:45)
- From: Moscow, Sovkhoznay 3, apt. 98
- Registered: 2014.07.08
- Posts: 3,896
- Likes: 497
Another difference, less noticeable and more difficult to reproduce, but sometimes capable of causing a lot of trouble, is resistance to changes in the system time. If you run the following test
setInterval(function() ( document.body.innerHTML = Math.random(); ), 500);
And after starting, translate the system time back a minute, then in the Firefox and Safari browsers, the change of numbers will stop, and in a minute it will start again. Of course, manual translation of the system time is an extremely rare situation, but many systems are configured to automatically synchronize time with servers on the Internet, so in some situations this factor cannot be discounted.
Another small minus of the setInterval function is that in order to be able to stop its action, you need to remember its identifier somewhere, which is not always convenient.
3 Reply by PunBB
- From: Moscow, Sovkhoznay 3, apt. 98
- Registered: 2014.07.08
- Posts: 3,896
- Likes: 497
Re: SetTimeOut and SetInterval, which is better to use in JavaScript?
To get rid of the listed shortcomings of setInterval, you can use multiple setTimeout.
An important alternative to setInterval is the recursive setTimeout:
/** instead of: var timerId = setInterval(function() ( alert("tick"); ), 2000); */ var timerId = setTimeout(function tick() ( alert("tick"); timerId = setTimeout(tick, 2000); ), 2000);
In the code above, the next execution is scheduled immediately after the previous one finishes.
The recursive setTimeout is a more flexible timing method than setInterval, since the time until the next execution can be scheduled differently, depending on the results of the current one.
For example, we have a service that polls the server every 5 seconds for new data. If the server is overloaded, you can increase the polling interval to 10, 20, 60 seconds ... And then return it back when everything is back to normal.
If we regularly run processor-loading tasks, then we can estimate the time spent on their execution and plan the next launch earlier or later.
4 Reply by PunBB
- From: Moscow, Sovkhoznay 3, apt. 98
- Registered: 2014.07.08
- Posts: 3,896
- Likes: 497
Re: SetTimeOut and SetInterval, which is better to use in JavaScript?
Recursive setTimeout guarantees a pause between calls, setInterval does not.
Let's compare two codes. The first one uses setInterval:
var i = 1; setInterval(function() ( func(i); ), 100);
The second one uses a recursive setTimeout:
var i = 1; setTimeout(function run() ( func(i); setTimeout(run, 100); ), 100);
With setInterval , the internal timer will fire exactly every 100ms and call func(i):
The real pause between func calls with setInterval is less than specified in the code!
This is natural, because the running time of the function is not taken into account in any way, it "eats" part of the interval.
It is also possible that func turned out to be more complicated than we expected and took longer than 100 ms.
In this case, the interpreter will wait for the function to complete, then check the timer and, if the time to call setInterval has already come up (or passed), then the next call will occur immediately.
If the function is executed longer than the setInterval pause, then the calls will occur without any interruption at all.
5 Reply by sempai
- From: Jerusalem
- Registered: 2015.06.02
- Posts: 958
- Likes: 274
Re: SetTimeOut and SetInterval, which is better to use in JavaScript?
Everything depends on the task at hand. Initially, SetTimeOut is used to start the timer once, and SetInterval is used to start the loop. But both functions can be used to cycle through scripts, if, for example, run recursively in the SetTimeOut function, then it will act practically similarly to SetInterval.
The minus of SetInterval at the moment is that it does not take into account the time for executing the script (function) itself, and if, for example, you use it for heavy queries, then the interval time will be significantly reduced, and it may differ in different browsers.
But again, if the function or request is minimized, then the end user is unlikely to feel the difference.
Therefore, what to use, everyone decides for himself.
In programming in scripting languages, from time to time there is a need to create a pause - to suspend the execution of the program for a while, and then continue working. For example, in VBS and PHP scripts, the following methods are possible:
VBS: wscript.sleep 1500 (stop for 1.5 seconds)
PHP: sleep(10); (stop for 10 seconds)
During these pauses, the runtime system (PHP or VBS) doing nothing. A developer trying to intuitively use something similar in Javascript will be unpleasantly surprised. A typical error when trying to create a pause in Javascript looks like this:
Function badtest() ( for (var i=1; i< 10; i++) { window.setTimeout("document.getElementById("test1").value += " + i, 900) } }
Do you think that when the queue reaches the drawing of the next digit during the loop, your setTimeout honestly stop Javascript work, wait 0.9 sec., add the required number to the end of the input field and then continue working. But actually it is not: setInterval and setTimeout in Javascript, only the action (or function) specified in parentheses is deferred. In our example, the following will happen:
- i = 1;
- postpone adding the number "1" to the input field by 0.9 seconds;
- immediately after setting this task, the cycle goes further: i=2;
- delay adding the number "2" to the input field by 0.9 seconds;
Immediately means, for example, 1 ms (that is, disproportionately small compared to 900 ms): the loop will perform its work almost instantly, creating several pending tasks from the same point in time. This means that all pending "drawing" tasks will be completed at almost the same time, with no pauses between adding new numbers. The cycle starts; everything freezes for 0.9 s; and shirrr - all numbers are shot in a row one after another.
How would you apply it in such a case? setTimeout? It's complicated. You have to call the function recursively(from inside the function the same function), and so that this process is not infinite, set a stop condition (for example, the value of the printed number):
Function welltest() ( if (i< 9) { document.getElementById("test2").value += ++i window.setTimeout("welltest()", 400) } }
And another variable i you have to initialize it outside the function - for example, like this:
Now everything works as it should (we reduced the delay time from 0.9 s to 0.4 s). But for such tasks it is more logical to use not setTimeout a setInterval(although this will require two functions):
Function besttest() ( window.i = 0 window.timer1 = window.setInterval("draw()", 400) ) function draw() ( document.getElementById("test3").value += ++i if (i >= 9) clearInterval(window.timer1) )
Feature of Javascirpt method setInterval in that it does not go away “by itself”, it must be stopped by a special method clearInterval. And to make it clear what exactly to stop, a special identifier is assigned to the task for the deferred action - a timer: window.timer1 = window.setInterval(...) .
Identifiers can also be assigned to tasks created by the method setTimeout. All timer IDs must be different from each other (be unique within the current browser window). Then you can create several different tasks in the window that use pending actions, and these tasks will be executed in parallel (like at the same time, if the computer has enough resources), which is basically impossible in PHP or VBS.
Here is an example page with multiple Javascript timers running at the same time: setinterval.htm (Javascript functions in setinterval.js). All page timers (except menus) can be stopped with the Esc key. All example timers rely on "natural" (rather than abstract) i++) counting - time or distance. All "clocks" are specially out of sync (for clarity). Distance-dependent timers are used in the "indicator" and in the drop-down ("driving") menu.
Drop-down menu
Our pull-out menu is really pull-out (from under the “header”): gaps are left between the elements to see how it slides out. Unexpectedly, it turned out that we cannot make equally smooth exit for lists of different lengths - probably due to low computer performance (AMD Athlon 999 MHz).
It is quite obvious that for beauty and harmony it is necessary that the lists of different menu items fall out at the same time. That is, longer lists should drop out at a higher rate, shorter ones at a slower rate. It would seem that this can be done like this:
- We set the total “departure” time, for example, to 200 ms.
- If the dropdown list is 20px high, obviously we can move it down one pixel per 10ms interval, and then the whole list will pop up in 200ms.
- If the dropdown is 40px high, to fit in at the same time we have to move it down one pixel every 5ms.
By this logic, if the dropdown has a height of 200px, we should move it down one pixel per 1ms. But such a speed does not work on our computer - the browser simply does not have time to draw a new position of the list in one millisecond. Yes. Javascript has time to count (what is there to count?), But the browser (Firefox) does not have time to display. A typical web situation.
Therefore, it is possible to more or less equalize the menu departure time only with the help of crutches, and it is still unclear how this will work for more fast computer. But we must count on the slowest one, right? The algorithm (without taking into account the speed of the computer) turns out to be something like this:
- Set the total time to leave the list: time = 224 (ms).
- Set the minimum time for one interval in the cycle: delay = 3 (ms).
- Set the minimum step for the movement of the list: offset = 1 (px).
- We change all this depending on the height of the list: 1) increase the delay (interval) time inversely proportional to the height and directly proportional to the total time time (at a height of 224, the coefficient is 1); 2) if the height is more than 40 px, increase the minimum step in proportion to the height. The constant "40" was obtained empirically for the slowest computer. Tests on a Pentium 4 CPU 2.53GHz computer revealed exactly the same number - 40. Otherwise, the timers run wild, the lists go out of step.
Now the lists are more or less leaving. More or less the same amount of time. On the setinterval.htm page.
Here's Bruce:
Function slide_do(obj, maxtop, offset) ( if (getTopLeft(obj).top< maxtop) { obj.style.top = getTopLeft(obj).top + offset } else { if (obj && obj.timer1) { clearInterval(obj.timer1) obj.timer1 = null } } }
The function itself, which pushes nested lists from the menu, as we see, is very simple. It remains only to run it with something like this line:
ts.timer1 = setInterval(function()(slide_do(ts, maxtop, offset)), delay)
Well, before running, just calculate all these maxtop and offset, and also put the list in the mintop position. What does the "preliminary" function do? slide() 40 lines in size. And all together - in the file setinterval.js . Yes, and this crap won't fucking work without a stylesheet included.
The setInterval() method, offered on the Window and Worker interfaces, 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() . This method is defined by the WindowOrWorkerGlobalScope mixin.
Syntax
varintervalID = scope.setInterval( func, delay, [arg1, arg2, ...]); varintervalID = scope.setInterval( code, delay);Parameters
func A function to be executed every delay milliseconds. The function is not passed any arguments, and no return value is expected. code An optional syntax allows you to include a string instead of a function, which is compiled and executed every delay milliseconds. This syntax is not recommended for the same reasons that make using eval() a security risk. delay The time, in milliseconds (thousandths of a second), the timer should delay in between executions of the specified function or code. See below for details on the permitted range of delay values. arg1, ..., argN Optional Additional arguments which are passed through to the function specified by func once the timer expires.note: Passing additional arguments to setInterval() in the first syntax does not work in Internet Explorer 9 and earlier. If you want to enable this functionality on that browser, you must use a polyfill (see the section).
return value
The returned intervalID is a numeric, non-zero value which identifies the timer created by the call to setInterval() ; this value can be passed to cancel the timeout.
It may be helpful to be aware that setInterval() and setTimeout() share the same pool of IDs, and that clearInterval() and clearTimeout() can technically be used interchangeably. For clarity, however, you should try to always match them to avoid confusion when maintaining your code.
note: The delay argument is converted to a signed 32-bit integer. This effectively limits delay to 2147483647 ms, since it's specified as a signed integer in the IDL.
Examples
Example 1: Basic syntax
The following example demonstrates setInterval() "s basic syntax.
Var intervalID = window.setInterval(myCallback, 500, "Parameter 1", "Parameter 2"); function myCallback(a, b) ( // Your code here // Parameters are purely optional. console.log(a); console.log(b); )
Example 2: Alternating two colors
The following example calls the flashtext() function once a second until the Stop button is pressed.
hello world
Example 3: Typewriter simulation
The following example simulates typewriter by first clearing and then slowly typing content into the NodeList that matches a specified group of selectors.
CopyLeft 2012 by Mozilla Developer Network
[ play | Pause | Terminate ]
JavaScript Typewriter
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices dolor ac dolor imperdiet ullamcorper. Suspendisse quam libero, luctus auctor mollis sed, malesuada condimentum magna. Quisque in ante tellus, in placerat est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a mi magna, quis mattis dolor. Etiam sit amet ligula quis urna auctor imperdiet nec faucibus ante. Mauris vel consectetur dolor. Nunc eget elit eget velit pulvinar fringilla consectetur aliquam purus. Curabitur convallis, justo posuere porta egestas, velit erat ornare tortor, non viverra justo diam eget arcu. Phasellus adipiscing fermentum nibh ac commodo. Nam turpis nunc, suscipit a hendrerit vitae, volutpat non ipsum.
Duis lobortis sapien quis nisl luctus porttitor. In tempor semper libero, eu tincidunt dolor eleifend sit amet. Ut nec velit in dolor tincidunt rhoncus non non diam. Morbi auctor ornare orci, non euismod felis gravida nec. Curabitur elementum nisi a eros rutrum nec blandit diam placerat. Aenean tincidunt risus ut nisi consectetur cursus. Ut vitae quam elit. Donec dignissim est in quam tempor consequat. Aliquam aliquam diam non felis convallis suscipit. Nulla facilisi. Donec lacus risus, dignissim et fringilla et, egestas veleros. Duis malesuada accumsan dui, at fringilla mauris bibStartum quis. Cras adipiscing ultricies fermentum. Praesent bibStartum condimentum feugiat.
Nam faucibus, ligula eu fringilla pulvinar, lectus tellus iaculis nunc, vitae scelerisque metus leo non metus. Proin mattis lobortis lobortis. Quisque accumsan faucibus erat, vel varius tortor ultricies ac. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec libero nunc. Nullam tortor nunc, elementum a consectetur et, ultrices eu orci. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque a nisl eu sem vehicula egestas.
callback arguments
As previously discussed, Internet Explorer versions 9 and below do not support the passing of arguments to the callback function in either setTimeout() or setInterval() . The following IE-specific code demonstrates a method for overcoming this limitation. To use, simply add the following code to the top of your script.
/*\ |*| |*| IE-specific polyfill that enables the passage of arbitrary arguments to the |*| callback functions of javascript timers (HTML5 standard syntax)..setInterval |*| https://website/User:fusionchess |*| |*| Syntax: |*| var timeoutID = window.setTimeout(func, delay[, arg1, arg2, ...]); |*| var timeoutID = window.setTimeout(code, delay); |*| var intervalID = window.setInterval(func, delay[, arg1, arg2, ...]); |*| var intervalID = window.setInterval(code, delay); |*| \*/ if (document.all && !window.setTimeout.isPolyfill) ( var __nativeST__ = window.setTimeout; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var aArgs = Array .prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay); ); window.setTimeout.isPolyfill = true; ) if (document.all && !window.setInterval.isPolyfill) ( var __nativeSI__ = window.setInterval; window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var aArgs = Array.prototype. slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () ( vCallback.apply(null, aArgs); ) : vCallback, nDelay); ); window.setInterval.isPolyfill = true; )Another possibility is to use an anonymous function to call your callback, although this solution is a bit more expensive. Example:
Var intervalID = setInterval(function() ( myFunc("one", "two", "three"); ), 1000); var intervalID = setInterval(function(arg1) ().bind(undefined, 10), 1000);
Inactive tabs
Requires Gecko 5.0(Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2)Starting in Gecko 5.0 (Firefox 5.0 / Thunderbird 5.0 / SeaMonkey 2.2), intervals are clamped to fire no more often than once per second in inactive tabs.
The "this" problem
When you pass a method to setInterval() or any other function, it is invoked with the wrong this value. This problem is explained in detail in the JavaScript reference .
Explanation
Code executed by setInterval() runs in a separate execution context than the function from which it was called. As a consequence, the this keyword for the called function is set to the window (or global) object, it is not the same as the this value for the function that called setTimeout . See the following example (which uses setTimeout() instead of setInterval() – the problem, in fact, is the same for both timers):
MyArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); myArray.myMethod(); // prints "zero,one,two" myArray.myMethod(1); // prints "one" setTimeout(myArray.myMethod, 1000); // prints "" after 1 second setTimeout(myArray.myMethod, 1500, "1"); // prints "undefined" after 1.5 seconds // passing the "this" object with .call won't work // because this will change the value of this inside setTimeout itself // while we want to change the value of this inside myArray.myMethod // in fact, it will be an error because setTimeout code expects this to be the window object: setTimeout.call(myArray, myArray.myMethod, 2000); // error: "NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object" setTimeout.call(myArray, myArray.myMethod, 2500, 2); // same error
As you can see there are no ways to pass the this object to the callback function in the legacy JavaScript.
A possible solution
A possible way to solve the " this " problem is to replace the two native setTimeout() or setInterval() global functions with two non-native ones that enable their invocation through the Function.prototype.call method. The following example shows a possible replacement:
// Enable the passage of the "this" object through the JavaScript timers var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval; window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeST__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); ); window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) ( var oThis = this, aArgs = Array.prototype.slice.call(arguments, 2); return __nativeSI__(vCallback instanceof Function ? function () ( vCallback.apply(oThis, aArgs); ) : vCallback, nDelay); );
These two replacements also enable the HTML5 standard passage of arbitrary arguments to the callback functions of timers in IE. So they can be used as non-standard-compliant polyfills also. See the for a standard-compliant polyfill.
New feature test:
MyArray = ["zero", "one", "two"]; myArray.myMethod = function (sProperty) ( alert(arguments.length > 0 ? this : this); ); setTimeout(alert, 1500, "Hello world!"); // the standard use of setTimeout and setInterval is preserved, but... setTimeout.call(myArray, myArray.myMethod, 2000); // prints "zero,one,two" after 2 seconds setTimeout.call(myArray, myArray.myMethod, 2500, 2); // prints "two" after 2.5 seconds
For a more complex but still modular version of it ( Daemon) see JavaScript Daemons Management . This more complex version is nothing but a big and scalable collection of methods for the Daemon constructor. However, the Daemon constructor itself is nothing but a clone of MiniDaemon with an added support for init and start functions declared during the instantiation of the daemon . So the MiniDaemon framework remains the recommended way for simple animations, because Daemon without its collection of methods is essentially a clone of it.
minidaemon.js
/*\ |*| |*| :: MiniDaemon:: |*| |*| Revision #2 - September 26, 2014.setInterval |*| https://website/User:fusionchess |*| https://github.com/madmurphy/minidaemon.js |*| |*| This framework is released under the GNU Lesser General Public License, version 3 or later. |*| http://www.gnu.org/licenses/lgpl-3.0.html |*| \*/ function MiniDaemon (oOwner, fTask, nRate, nLen) ( if (!(this && this instanceof MiniDaemon)) ( return; ) if (arguments.length< 2) { throw new TypeError("MiniDaemon - not enough arguments"); } if (oOwner) { this.owner = oOwner; } this.task = fTask; if (isFinite(nRate) && nRate >0) ( this.rate = Math.floor(nRate); ) if (nLen > 0) ( this.length = Math.floor(nLen); ) ) MiniDaemon.prototype.owner = null; MiniDaemon.prototype.task = null; MiniDaemon.prototype.rate = 100; MiniDaemon.prototype.length = Infinity; /* These properties should be read-only */ MiniDaemon.prototype.SESSION = -1; MiniDaemon.prototype.INDEX = 0; MiniDaemon.prototype.PAUSED = true; MiniDaemon.prototype.BACKW = true; /* Global methods */ MiniDaemon.forceCall = function (oDmn) ( oDmn.INDEX += oDmn.BACKW ? -1: 1; if (oDmn.task.call(oDmn.owner, oDmn.INDEX, oDmn.length, oDmn .BACKW) === false || oDmn.isAtEnd()) ( oDmn.pause(); return false; ) return true; ); /* Instances methods */ MiniDaemon.prototype.isAtEnd = function () ( return this.BACKW ? isFinite(this.length) && this.INDEX< 1: this.INDEX + 1 >this.length; ); MiniDaemon.prototype.synchronize = function () ( if (this.PAUSED) ( return; ) clearInterval(this.SESSION); this.SESSION = setInterval(MiniDaemon.forceCall, this.rate, this); ); MiniDaemon.prototype.pause = function () ( clearInterval(this.SESSION); this.PAUSED = true; ); MiniDaemon.prototype.start = function (bReverse) ( var bBackw = Boolean(bReverse); if (this.BACKW === bBackw && (this.isAtEnd() || !this.PAUSED)) ( return; ) this.BACKW = bBackw; this.PAUSED = false; this.synchronize(); );MiniDaemon passes arguments to the callback function. If you want to work on it with browsers that natively do not support this feature, use one of the methods proposed above.
Syntax
var myDaemon = new MiniDaemon( thisObject, callback[ , rate [, length]]);
Description
Usage notes
The setInterval() function is commonly used to set a delay for functions that are executed again and again, such as animations. You can cancel the interval using WindowOrWorkerGlobalScope.clearInterval() .
If you wish to have your function called once after the specified delay, use .
Delay restrictions
It "s possible for intervals to be nested; that is, the callback for setInterval() can in turn call setInterval() to start another interval running, even though the first one is still going. To mitigate the potential impact this can have on performance, once intervals are nested beyond five levels deep, the browser will automatically enforce a 4 ms minimum value for the interval.
Browsers may enforce even more stringent minimum values for the interval under some circumstances, although these should not be common. Note also that the actual amount of time that elapses between calls to the callback may be longer than the given delay ; see Reasons for delays longer than specified in WindowOrWorkerGlobalScope.setTimeout() for examples.
Ensure that execution duration is shorter than interval frequency
If there is a possibility that your logic could take longer to execute than the interval time, it is recommended that you recursively call a named function using setTimeout() . For example, if using setInterval() to poll a remote server every 5 seconds, network latency, an unresponsive server, and a host of other issues could prevent the request from completing in its allotted time. As such, you may find yourself with queued up XHR requests that won't necessarily return in order.
Source: http://learn.javascript.ru/settimeout-setinterval
Almost all JavaScript implementations have an internal scheduler that allows you to schedule a function to be called after a given period of time.
In particular, this feature is supported in browsers and in the Node.JS server.
setTimeout
Syntax:
var timerId = setTimeout(func/code, delay[, arg1, arg2...])Parameters:
- func/code
- The function or line of code to execute.
- The string is supported for compatibility and is not recommended.
- delay
- Delay in milliseconds, 1000 milliseconds equals 1 second.
- arg1, arg2…
- Arguments to pass to the function. Not supported in IE9-.
- The function will be executed after the time specified in the delay parameter.
For example, the following code will call alert("Hi") after one second:
func()( alert("Hi" ); ) setTimeout(func, 1000 );If the first argument is a string, then the interpreter creates an anonymous function from that string.
That is, such an entry works exactly the same:
SetTimeout("alert("Hello")" , 1000 );
Instead, use anonymous functions:
SetTimeout( function()( alert("Hi" ) ), 1000 );
Function parameters and context
In all modern browsers, considering IE10, setTimeout allows you to specify function parameters.
The example below will output "Hi, I'm Vasya" everywhere except IE9-:
function sayHi(who)( alert("Hi, I'm " + who); ) setTimeout(sayHi, 1000 , "Vasya" );…However, in most cases, we need support for the old IE, and it does not allow you to specify arguments. Therefore, in order to pass them, they wrap the call in an anonymous function:
function sayHi(who)( alert("Hi, I'm " + who); ) setTimeout( function()( sayHi("Vasya" ) ), 1000 );Calling via setTimeout does not pass the this context.
In particular, calling an object method via setTimeout will work in the global context. This may lead to incorrect results.
For example, let's call user.sayHi() after one second:
function User (id) function()( alert(this .id); ); ) var user = new User(12345 ); setTimeout(user.sayHi, 1000 ); // expected 12345 but will print "undefined"Since setTimeout will run the user.sayHi function in the global context, it will not have access to the object via this .
In other words, these two setTimeout calls do the same thing:
// (1) one line setTimeout(user.sayHi, 1000 ); // (2) the same in two lines var func = user.sayHi; setTimeout(func, 1000 );Fortunately, this problem is also easily solved by creating an intermediate function:
function User (id)( this .id = id; this .sayHi = function()( alert(this .id); ); ) var user = new User(12345 ); setTimeout( function()( user.sayHi(); ), 1000 );A wrapper function is used to pass arguments cross-browser and preserve the execution context.
Cancel execution
The setTimeout function returns a timerId that can be used to cancel the action.
Syntax:
ClearTimeout(timerId)
In the following example, we set a timeout and then delete (change our mind). As a result, nothing happens.
var timerId = setTimeout( function()( alert(1 ) ), 1000 ); clearTimeout(timerId);setInterval
The setInterval method has a syntax similar to setTimeout .
var timerId = setInterval(func/code, delay[, arg1, arg2...])The meaning of the arguments is the same. But, unlike setTimeout , it does not run the function once, but regularly repeats it after a specified time interval. You can stop execution by calling:
ClearInterval(timerId)
The following example, when run, will display a message every two seconds until you click on the Stop button:
<input type ="button" onclick ="clearInterval(timer)" value ="(!LANG:Stop" > !} <script> var i = 1 ; var timer = setInterval( function()( alert(i++) ), 2000 );script>Queuing and stacking calls in setInterval
Calling setInterval(function, delay) sets the function to execute after the specified time interval. But there is a subtlety here.
In fact, the pause between calls is less than the specified interval.
For example, let's take setInterval(function() ( func(i++) ), 100) . It executes func every 100ms, incrementing the counter each time.
In the picture below, the red block is the execution time of func . The time between blocks is the time between function runs and is less than the set delay!
That is, the browser initiates the execution of the function exactly every 100ms, without taking into account the execution time of the function itself.
It happens that the execution of a function takes more time than the delay. For example, the function is complex and the delay is small. Or the function contains alert / confirm / prompt statements that block the flow of execution. In this case, interesting things begin.
If the function cannot be launched because the browser is busy, it gets queued and will be executed as soon as the browser is free.
The image below illustrates what happens for a function that takes a long time to execute.
A function call triggered by setInterval is added to the queue and fires immediately when possible:
The second run of the function occurs immediately after the end of the first:
Execution is not queued more than once.
If the execution of a function takes longer than several scheduled executions, then it will still be queued once. So there is no "accumulation" of launches.
In the image below, setInterval tries to execute the function in 200ms and queues the call. At 300ms and 400ms, the timer wakes up again, but nothing happens.
Calling setInterval(function, delay) does not guarantee a real delay between executions.
There are times when the actual delay is greater or less than the specified one. In general, it is not a fact that there will be at least some kind of delay.
Repeat nested setTimeout
In cases where you need not just a regular repetition, but a delay between runs, you can use setTimeout to be set again every time the function is executed.
Below is an example that issues an alert with 2 second intervals between them.
<input type ="button" onclick ="clearTimeout(timer)" value ="(!LANG:Stop" > !} <script> var i = 1 ; var timer = setTimeout( function run()( alert(i++); timer = setTimeout(run, 2000 ); ), 2000 );script>There will be fixed delays between runs on the execution timeline. Illustration for 100ms delay:
Minimum timer delay
The browser timer has the lowest possible delay. It varies from about zero to 4ms in modern browsers. In older ones, it can be larger and reach 15ms.
By default, the minimum delay is 4ms. So there is no difference between setTimeout(..,1) and setTimeout(..,4) .
There are browser-specific behaviors in setTimeout and setInterval with zero delay.
- In Opera, setTimeout(.., 0) is the same as setTimeout(.., 4) . It is executed less frequently than setTimeout(..,2). This is a feature of this browser.
- In Internet Explorer, setInterval(.., 0) to zero delay won't work. This applies specifically to setInterval , i.e. setTimeout(.., 0) works fine.
Actual operating frequency
Operation may be much less frequent. In some cases, the delay may not be 4ms, but 30ms or even 1000ms.
Most browsers (desktop in the first place) continue to execute setTimeout / setInterval even if the tab is inactive. At the same time, a number of them (Chrome, FF, IE10) reduce the minimum timer frequency, up to 1 time per second. It turns out that the timer will fire in the "background" tab, but rarely.
When running on battery, in a laptop, browsers can also slow down to execute code less frequently and conserve battery power. IE is especially known for this. The reduction can reach several times, depending on the settings. If the CPU load is too high, JavaScript may not be able to process the timers in time. This will skip some runs of setInterval.
Conclusion: it is worth focusing on a frequency of 4ms, but you should not count on it.
Outputting intervals to the console The code that counts the time intervals between calls looks something like this:
var timeMark = new Date ; setTimeout( function go()( var diff = new Date - timeMark; // print the next delay to the console instead of the page console .log(diff); // remember the time at the very end, // to measure the delay exactly between calls timeMark = new Date ; setTimeout(go, 100); ), 100 );setTimeout(func, 0) trick
This trick deserves entry into the annals of JavaScript hacks.
The function is wrapped in setTimeout(func, 0) if they want to run it after the end of the current script.
The point is that setTimeout never executes the function right away. He only plans to carry it out. But the JavaScript interpreter will start executing the scheduled functions only after the execution of the current script.
By default, setTimeout cannot execute a function with a delay of 0 anyway. As we said before, the delay is typically 4ms. But the main thing here is that the execution in any case will be after the execution of the current code.
For example:
varresult; function showResult()( alert(result); ) setTimeout(showResult, 0 ); result = 2 *2 ; // prints 4Total
The setInterval(func, delay) and setTimeout(func, delay) methods allow func to run regularly/once every delay milliseconds.
Both methods return the ID of the timer. It is used to stop execution by calling clearInterval / clearTimeout .
| | setinterval | setTimeout | || ----------- | ---------- | | Timing | There is a call strictly on the timer. If the interpreter is busy, one call is queued. The execution time of the function is not taken into account, so the time interval from the end of one run to the start of another may be different. | The recursive call to setTimeout is used instead of setInterval where a fixed pause between executions is needed. | | Delay | Minimum delay: 4ms. | Minimum delay: 4ms. | | Browser features | Delay 0 doesn't work in IE. | In Opera, zero delay is equivalent to 4ms, other delays are handled exactly, including the non-standard 1ms, 2ms, and 3ms. |
It is extremely important to understand how JavaScript timers work. Often their behavior does not coincide with our intuitive perception of multithreading, and this is due to the fact that they actually run on the same thread. Let's look at four functions with which we can control timers:
- var id = setTimeout(fn, delay); - Creates a simple timer that will call the given function after the given delay. The function returns a unique ID with which the timer can be paused.
- var id = setInterval(fn, delay); - Similar to setTimeout, but continuously calls the function at a given interval (until it is stopped).
- clearInterval(id); clearTimeout(id); - Accepts a timer ID (returned by one of the functions described above) and stops callback"a from executing.
There is quite a lot of information in this figure that needs to be digested, but understanding this will give you a deeper understanding of how JavaScript asynchronous execution works. this chart represents time in milliseconds vertically, the blue boxes show blocks of JavaScript code that has been executed. For example, the first block executes in an average of 18ms, a mouse click blocks execution for approximately 11ms, and so on.
JavaScript can only execute one piece of code (due to the single-threaded nature of execution), each blocking the execution of other asynchronous events. This means that when an asynchronous event occurs (such as a mouse click, a timer is called, or an XMLHttp request completes), it is added to a queue and executed later (implementation varies by browser, of course, but let's call it a "queue") .
To begin with, let's imagine that two timers start inside the JavaScript block: setTimeout with a delay of 10ms and setInterval with the same delay. Depending on when the timer starts, it will fire at a time when we have not yet completed the first block of code. Note, however, that it does not fire immediately (this is not possible due to single-threading). Instead, the deferred function is queued and executed at the next available moment.
Also, during the execution of the first JavaScript block, a mouse click occurs. The handler for this asynchronous event (and it is asynchronous, because we cannot predict it) cannot be executed directly at this moment, so it also gets queued, just like the timer.
After the first block of JavaScript code has been executed, the browser asks itself the question "What is waiting for execution?". In this case, the mouse click handler and the timer are in a pending state. The browser chooses one of them (the click handler) and executes it. The timer will wait for the next available chunk of time in the execution queue.
Note that while the mouse click handler is executing, the first interval-callback is fired. Just like timer-callback, it will be queued. However, note that when the interval fires again (while the timer-callback is running), it will be removed from the queue. If all interval-callbacks were to queue up while a large piece of code is executing, this would result in a bunch of functions waiting to be called with no periods of delay between the end of their execution. Instead, browsers tend to wait until there is no function left in the queue before adding another one to the queue.
Thus, we can observe the case when the third firing of the interval-callback coincides with the moment when it is already executing. This illustrates important feature: intervals don't care what is currently running, they will be added to the queue regardless of the delay period between executions.
Finally, after the second interval-callback completes, we see that there is nothing left for the JavaScript engine to execute. This means that the browser is again waiting for new asynchronous events. This will happen at the 50ms mark, where the interval-callback will fire again. At that moment, there will be nothing to block it, so it will work immediately.
Let's look at an example that illustrates well the difference between setTimeout and setInterval.
setTimeout(function()( /* Some long block of code... */ setTimeout(arguments.callee, 10); ), 10); setInterval(function()( /* Some long block of code... */ ), 10);
These two options are equivalent at first glance, but in fact they are not. Code using setTimeout will always have a delay of at least 10ms after the previous call (it can be longer, but never less), while code using setInterval will tend to be called every 10ms, regardless of when the previous call ended.
Let's summarize all of the above:
- JavaScript engines use a single-threaded environment, converting asynchronous events into a queue waiting to be executed,
- The setTimeout and setInterval functions are executed fundamentally differently in asynchronous code,
- If the timer cannot be executed in this moment, it will be delayed until the next execution point (which will be longer than the desired delay),
- Intervals (setInterval) can be executed one after another without delay if their execution takes longer than the specified delay.
All this is extremely important information for development. Knowing how the JavaScript engine works, especially with a lot of asynchronous events (which happens a lot), lays a great foundation for building advanced applications.