Internet Windows Android

Javascript prevent multiple setinterval timers from running concurrently. Timers in Javascript (setInterval, setTimeout)

JavaScript timeout is a native javascript function that executes a piece of code after a specified time delay (in milliseconds). This can come in handy when you need to display a popup after the user has spent some time on your page. Or you want the effect to start when you hover the cursor over an element only after some time. This way, you can avoid inadvertent triggering of the effect if the user hovers over by accident.

Simple setTimeout example

To demonstrate the effect of this function, I suggest taking a look at the following demo, in which a pop-up window appears two seconds after the button is clicked.

View demo

Syntax

The MDN documentation provides the following syntax for setTimeout:

var timeoutID = window.setTimeout (func,); var timeoutID = window.setTimeout (code,);

  • timeoutID is a numeric id that can be used in conjunction with clearTimeout () to disable the timer;
  • func is the function to be executed;
  • code ( in alternative syntax) - the line of code to be executed;
  • delay - the duration of the delay in milliseconds after which the function will run. The default is 0.

setTimeout vs window.setTimeout

The above syntax uses window.setTimeout. Why?

In fact, setTimeout and window.setTimeout are practically the same function. The only difference is that in the second statement, we use the setTimeout method as a property of the global window object.

Personally, I think this only complicates the code a lot. If we were to define an alternative JavaScript timeout method that can be found and returned in priority order, we would run into even bigger problems.

In this tutorial, I don't want to mess with the window object, but in general, you decide which syntax to use.

Examples of using

This could be the name of the function:

function explode () (alert ("Boom!");) setTimeout (explode, 2000);

Variable that refers to the function:

var explode = function () (alert ("Boom!");); setTimeout (explode, 2000);

Or an anonymous function:

setTimeout (function () (alert ("Boom!");), 2000);

  • Such code is poorly understood, and, therefore, it will be difficult to modernize or debug;
  • It involves the use of the eval () method, which could be a potential vulnerability;
  • This method is slower than others because it needs to run JavaScript interpreter.

Also note that we are using the alert method for JavaScript timeout to test the code.

Passing parameters to setTimout

In the first ( besides, cross-browser) variant, we pass parameters to the callback function executed with setTimeout.

In the following example, we extract a random greeting from the greetings array and pass it as a parameter to the greet () function, which is executed by setTimeout with a 1 second delay:

function greet (greeting) (console.log (greeting);) function getRandom (arr) (return arr;) var greetings = ["Hello", "Bonjour", "Guten Tag"], randomGreeting = getRandom (greetings); setTimeout (function () (greet (randomGreeting);), 1000);

View demo

Alternative method

In the syntax at the beginning of this article, there is another method that can be used to pass parameters to the callback function executed by JavaScript timeout. This method implies the output of all parameters following the delay.

Building on the previous example, we get:

setTimeout (greet, 1000, randomGreeting);

This method will not work in IE 9 and below, where the passed parameters are undefined. But to solve this problem on MDN has a special polyfill.

Related problems and "this"

The code executed by setTimeout runs separately from the function that called it. Because of this, we are faced with certain problems, the this keyword can be used as a solution.

var person = (firstName: "Jim", introduce: function () (console.log ("Hi, I" m "+ this.firstName);)); person.introduce (); // Outputs: Hi, I" m Jim setTimeout (person.introduce, 50); // Outputs: Hi, I "m undefined

The reason for this conclusion lies in the fact that in the first example this leads to the person object, and in the second example it points to the global window object, which does not have the firstName property.

To get rid of this inconsistency, you can use several methods:

Force this to be set

This can be done using bind (), a method that creates a new function that, when called as the value of the this key, uses a specific value. In our case, the specified person object. This gives us as a result:

setTimeout (person.introduce.bind (person), 50);

Note: bind was introduced in ECMAScript 5, which means it will only work in modern browsers. In others, you will get a runtime error when you apply it JavaScript "function timeout error".

Use library

Many libraries include built-in functions needed to solve this problem. For example, the jQuery.proxy () method. It takes a function and returns a new one, in which it will always use a specific context. In our case, the context will be:

setTimeout ($. proxy (person.introduce, person), 50);

View demo

Disable timer

The return value of setTimeout is a numeric id that can be used to disable the timer using the clearTimeout () function:

var timer = setTimeout (myFunction, 3000); clearTimeout (timer);

Let's see it in action. In the next example, if you click on the button " Start countdown”, The countdown starts. After it is over, the kittens will get theirs. But if you press the button " Stop countdown", The JavaScript timeout will be stopped and reset.

View example

Let's summarize

setTimeout is an asynchronous function, which means that the received call to this function is queued and will be executed only after all other actions on the stack have completed. It cannot run concurrently with other functions or a separate thread.

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

var intervalID = scope.setInterval ( func, delay, [arg1, arg2, ...]); var intervalID = 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 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.

setInterval / clearInterval example

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.

JavaScript Typewriter - MDN Example

CopyLeft 2012 by Mozilla Developer Network

[ Play | Pause | Terminate ]

Vivamus blandit massa ut metus mattis in fringilla lectus imperdiet. Proin ac ante a felis ornare vehicula. Fusce pellentesque lacus vitae eros convallis ut mollis magna pellentesque. Pellentesque placerat enim at lacus ultricies vitae facilisis nisi fringilla. In tincidunt tincidunt tincidunt.

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.

Phasellus ac nisl lorem:

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 vel eros. 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: // site / 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 onstart functions declarable 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: // site / 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.Attempts to specify a value less than 4 ms in deeply-nested calls to setInterval () will be pinned to 4 ms.

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.

  • From:
  • Registered: 2014.07.08
  • Posts: 3,896
  • Likes: 497

Topic: SetTimeOut and SetInterval, which is better to use in JavaScript?

To run the code multiple times at regular intervals, the function setInterval... However, it has a number of drawbacks, mainly different behavior in different browsers.

The first difference is the difference when the timer is set for the next start. Let's create a small test: we will measure the amount of time elapsed from the beginning 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 only difference will be in the range of values. Smallest variation 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 that is less noticeable and more difficult to reproduce, but sometimes can cause a lot of trouble, is the resistance to changes in the system time. If you run the next test

setInterval (function () (document.body.innerHTML = Math.random ();), 500);

And after starting, set the system time back a minute, then in Firefox and Safari browsers the change of numbers will pause, and after 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 disregarded.

Another small disadvantage 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 disadvantages of setInterval, you can use multiple setTimeout.

An important alternative to setInterval is 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 end of the previous one.

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 for new data every 5 seconds. If the server is overloaded, you can increase the polling interval to 10, 20, 60 seconds ... And then return it back when everything is normalized.

If we regularly have tasks that load the processor, then we can estimate the time spent on their execution and schedule the next launch sooner 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 the two codes. The first one uses setInterval:

var i = 1; setInterval (function () (func (i);), 100);

The second 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 what is 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 to execute.

In this case, the interpreter will wait for the function to complete, then check the timer and, if the time for calling setInterval has already come (or passed), then the next call will occur immediately.

If the function takes longer than the setInterval pause, then the calls will occur without 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?

It all depends on the task at hand. Initially, SetTimeOut is used to start the timer once, and SetInterval to start the loop. But both functions can be used to loop through scripts, if, for example, run recursively in the SetTimeOut function, it will act in a practical way similar to SetInterval.

The disadvantage of SetInterval at the moment is that it does not take into account the execution time of the script (function) itself, and if, for example, you use it for heavy requests, then the interval time will be significantly reduced, and it may differ in different browsers.

But again, I repeat, 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.

Source: http://learn.javascript.ru/settimeout-setinterval

Almost all JavaScript implementations have an internal scheduling timer that allows you to schedule a function call after a specified 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 ...])

Options:

  • func / code
    • A function or line of code to execute.
    • The string is supported for compatibility and is deprecated.
  • 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 ("Hello") after one second:

function func ()(alert ("Hello");) setTimeout (func, 1000);

If the first argument is a string, then the interpreter creates an anonymous function from that string.

That is, such a record works in exactly the same way:

SetTimeout ("alert (" Hello ")", 1000);

Use anonymous functions instead:

SetTimeout ( function ()(alert ("Hello")), 1000);

Function parameters and context

In all modern browsers, with IE10 in mind, setTimeout allows you to specify function parameters.

The example below will display "Hi, I'm Vasya" everywhere except IE9-:

function sayHi (who)(alert ("Hello, 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, the call is wrapped in an anonymous function:

function sayHi (who)(alert ("Hello, me" + who);) setTimeout ( function ()(sayHi ("Vasya")), 1000);

Calling through setTimeout does not pass this context.

In particular, calling an object's method via setTimeout will work in the global context. This can 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 be able to access the object via this.

In other words, these two calls to setTimeout do the same thing:

// (1) one line setTimeout (user.sayHi, 1000); // (2) same thing 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);

The wrapper function is used to cross-browser pass arguments and store the execution context.

Cancel execution

The setTimeout function returns a timerId that can be used to cancel an 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 starts the execution of the function not once, but regularly repeats it at a specified time interval. You can stop execution by calling:

ClearInterval (timerId)

The following example, at startup, 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 overlaying calls in setInterval

Calling setInterval (function, delay) puts the function to be executed 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 block is the time between starts of the function, and it is less than the set delay!

That is, the browser initiates the launch of the function neatly every 100ms, without taking into account the execution time of the function itself.

It happens that the execution of a function takes longer than the delay. For example, the function is complex and the latency is small. Or the function contains alert / confirm / prompt statements that block the execution thread. In this case, interesting things begin.

If the function cannot be started because the browser is busy, it is queued and executed as soon as the browser is free.

The image below illustrates what is happening for a function that takes a long time to execute.

A function call initiated by setInterval is added to the queue and occurs immediately when it becomes possible:

The second run of the function occurs immediately after the end of the first:

The execution is not queued more than once.

If the execution of a function takes longer than several scheduled executions, then it will still queue up once. So there is no "accumulation" of launches.

In the image below, setInterval tries to execute the function in 200ms and enqueues the call. At 300ms and 400ms, the timer wakes up again, but nothing goes through.

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.

Repetition of nested setTimeout

In cases where not just regular repetition is needed, but a delay between starts is required, setTimeout is reset every time the function is executed.

Below is an example that emits 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 latency. It varies from about zero to 4ms in modern browsers. In older ones, it can be higher and reach 15ms.

By standard, the minimum delay is 4ms. So there is no difference between setTimeout (.., 1) and setTimeout (.., 4).

The zero-latency setTimeout and setInterval behaviors are browser-specific.

  1. In Opera, setTimeout (.., 0) is the same as setTimeout (.., 4). It runs less frequently than setTimeout (.., 2). This is a feature of this browser.
  2. In Internet Explorer, a zero delay setInterval (.., 0) will not work. This applies specifically to setInterval, i.e. setTimeout (.., 0) works fine.

Actual response frequency

Triggering 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, down to 1 time per second. It turns out that a timer will be triggered in the "background" tab, but rarely.

When running on battery power, in a laptop - browsers can also lower the frequency in order to execute code less often and conserve battery power. IE is especially famous for this. The reduction can be up to several times, depending on the settings. If the processor load is too heavy, JavaScript may not be able to process the timers in time. This will skip some of the setInterval runs.

Conclusion: you should be guided by the 4ms frequency, but you shouldn't count on it.

Outputting the intervals to the console The code that counts the intervals between calls looks something like this:

var timeMark = new Date; setTimeout ( function go ()(var diff = new Date - timeMark; // print another delay to the console instead of a 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 );

The setTimeout (func, 0) trick

This trick is worthy of entering the annals of JavaScript hacks.

The function is wrapped in setTimeout (func, 0) if you want to run it after the end of the current script.

The point is that setTimeout never executes a function right away. He only plans its implementation. But the JavaScript interpreter will start executing the planned functions only after the execution of the current script.

By standard, setTimeout cannot execute a function with a delay of 0 anyway. As we said earlier, usually the delay will be 4ms. But the main thing here is that execution in any case will be after the execution of the current code.

For example:

var result; function showResult ()(alert (result);) setTimeout (showResult, 0); result = 2 * 2; // will print 4

Total

The setInterval (func, delay) and setTimeout (func, delay) methods allow func to be run regularly / once after delay milliseconds.

Both methods return the timer ID. It is used to stop execution by calling clearInterval / clearTimeout.

| | setInterval | setTimeout | || ----------- | ---------- | | Timing | A call is in progress strictly on a timer. If the interpreter is busy, one call enters the queue. The execution time of the function is not taken into account, so the time interval from the end of one run to the beginning of another can be different. | A 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 does not work in IE | In Opera, zero latency is equivalent to 4ms, other delays are handled accurately, including non-standard 1ms, 2ms and 3ms. |

In programming in scripting languages, it is periodically necessary 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 such pauses, the runtime system (PHP or VBS) doing nothing... A developer trying to intuitively use something like this 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, when passing through the loop, it comes to drawing the next digit, your setTimeout will honestly stop the work of Javascript, wait 0.9 seconds, 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 delayed. In our example, the following will happen:

  1. i = 1;
  2. postpone adding the number "1" to the input field by 0.9 seconds;
  3. immediately after setting this problem, the cycle goes on: i = 2;
  4. postpone adding the number "2" to the input field by 0.9 seconds;

Immediately means, for example, 1 ms (that is, incommensurably small, compared to 900 ms): the cycle 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, without 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.

And how, in such a case, it is correct to apply setTimeout? It's complicated. Have to call the function recursively(from inside the function, the same function), and so that this process is not infinite, set the 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 will have to be initialized 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 the Javascirpt method setInterval the fact that it does not pass "by itself", it must be stopped by a special method clearInterval... And to make it clear what to stop, the deferred action task is assigned a special identifier - 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 (unique within the current browser window). Then you can create several different tasks in the window that use deferred actions, and these tasks will be executed in parallel (sort of like simultaneously, if the computer has enough resources), which is basically impossible in PHP or VBS.

Here is an example of a page with several Javascript timers running at the same time: setinterval.htm (Javascript functions in setinterval.js file). The operation of all page timers (except for the menu) can be stopped by pressing the Esc key. All example timers rely on "natural" (not abstract i ++) countdown - time or distance. All "clocks" are specially desynchronized (for clarity). Distance-based timers are used in the "indicator" and in the pull-down (pull-down) menu.

Drop-down menu

Our pull-out menu is actually pull-out (from under the "header"): there are gaps between the elements to see how it pulls out. Unexpectedly, it turned out that we cannot make an equally smooth exit for lists of different lengths - probably due to the low performance of the computer (AMD Athlon 999 MHz).

It is quite obvious that for beauty and harmony it is necessary that lists of different menu items appear at the same time. That is, longer lists should drop out at a faster rate, shorter ones - at a lower rate. It would seem that this can be implemented like this:

  1. We set the total time of "departure", for example, in 200 ms.
  2. If the drop-down list has a height of 20 px, it is obvious that we can move it down one pixel at a time of 10 ms - and then in 200 ms the entire list will pop up.
  3. If the dropdown is 40px high, to fit at the same time, we have to move it down one pixel at a time in 5ms.

According to this logic, if the drop-down list is 200 px high, we must move it down one pixel at a time in 1 ms. But this speed does not work on our computer - the browser simply does not have time to draw the new position of the list in one millisecond. Yes. Javascript has time to count (what is there to count?), And the browser (Firefox) does not have time to display. A typical situation for the web.

Therefore, it is possible to more or less equalize the time for leaving the menu only with the help of crutches, and it is still unclear how this will work on a faster 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:

  1. We set the total checkout time of the list: time = 224 (ms).
  2. We set the minimum time for one interval in the cycle: delay = 3 (ms).
  3. Set the minimum step for moving the list: offset = 1 (px).
  4. We change all this depending on the height of the list: 1) increase the delay (interval) time in inverse proportion to the height and in direct proportion 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 proportionally to the height. Constant "40" is obtained empirically for the slowest computer. Tests on a Pentium 4 CPU 2.53GHz computer showed exactly the same number - 40. Otherwise, timers are out of step, lists are out of step.

Now the lists are more or less rolling out. For a more or less similar time. On the setinterval.htm page.

And here is Bru-mustache:

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 brings nested lists out of the menu, is, as you can see, 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 starting, just calculate all these maxtop and offset, and also put the list in the mintop position. What the "preliminary" function does slide () 40 lines in size. And all together - in the setinterval.js file. Yes, and this crap won't work without an included stylesheet.