**setTimeout**
is a native JavaScript function (although it can be used with a library such as jQuery, as we’ll see later on), which calls a function or executes a code snippet after a specified delay (in milliseconds). This might be useful if, for example, you wished to display a popup after a visitor has been browsing your page for a certain amount of time, or you want a short delay before removing a hover effect from an element (in case the user accidentally moused out).
**![set_timeout_2-01](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2015/08/1476830355set_timeout_2-01.png)**
This popular article was updated in 2020.
To demonstrate the concept, the following demo displays a popup, two seconds after the button is clicked.
If you don’t see the popup open, please visit CodePen and run the demo there.
From the MDN documentation, the syntax for setTimeout
is as follows:
var timeoutID = scope.setTimeout(function[, delay, arg1, arg2, ...]);
var timeoutID = scope.setTimeout(function[, delay]);
var timeoutID = scope.setTimeout(code[, delay]);
where:
timeoutID
is a numerical ID, which can be used in conjunction with clearTimeout to cancel the timer.scope
refers to the Window interface or the WorkerGlobalScope interface.function
is the function to be executed after the timer expires.code
is an alternative syntax that allows you to include a string instead of a function, which is compiled and executed when the timer expires.delay
is the number of milliseconds by which the function call should be delayed. If omitted, this defaults to 0.arg1, ..., argN
are additional arguments passed to the function specified by function
.Note: the square brackets _[]_
denote optional parameters.
You’ll notice that the syntax above uses scope.setTimeout
. Why is this?
Well, when running code in the browser, scope
would refer to the global window
object. Both setTimeout
and window.setTimeout
refer to the same function, the only difference being that in the second statement we are referencing the setTimeout
method as a property of the window
object.
In my opinion, this adds complexity for little or no benefit. If you’ve defined an alternative setTimeout
method which would be found and returned in priority in the scope chain, then you’ve probably got bigger problems to worry about.
For the purposes of this tutorial, I’ll omit window
, but ultimately, which syntax you choose is up to you.
setTimeout
accepts a reference to a function as the first argument.
This can be the name of a function:
function greet(){
alert('Howdy!');
}
setTimeout(greet, 2000);
A variable that refers to a function (a function expression):
const greet = function(){
alert('Howdy!');
};
setTimeout(greet, 2000);
Or an anonymous function:
setTimeout(() => { alert('Howdy!'); }, 2000);
As noted above, it’s also possible to pass setTimeout
a string of code for it to execute:
setTimeout('alert("Howdy!");', 2000);
However, this is not advisable for the following reasons:
eval
, which is a potential security risk.This Stack Overflow question offers more information on the above points.
In a basic scenario, the preferred, cross-browser way to pass parameters to a callback executed by setTimeout
is by using an anonymous function as the first argument.
In the following example, we select a random animal from an animals
array and pass this random animal as a parameter to a makeTalk
function. The makeTalk
function is then executed by setTimeout
with a delay of one second:
function makeTalk(animal){
const noises = {
cat: 'purr',
dog: 'woof',
cow: 'moo',
pig: 'oink',
}
console.log(`A ${animal} goes ${noises[animal]}.`);
}
function getRandom (arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
const animals = ['cat', 'dog', 'cow', 'pig'];
const randomAnimal = getRandom(animals);
setTimeout(() => {
makeTalk(randomAnimal);
}, 1000);
Note: I’ve used a regular function (_getRandom_
) to return a random element from an array. It would also be possible to write this as a function expression using an arrow function:
const getRandom = arr => arr[Math.floor(Math.random()*arr.length)];
We’ll get to arrow functions in the next section.
As can be seen from the syntax at the top of the article, there’s a second method of passing parameters to a callback executed by setTimeout
. This involves listing any parameters after the delay.
With reference to our previous example, this would give us:
setTimeout(makeTalk, 1000, randomAnimal);
Unfortunately, this doesn’t work in IE9 or below, where the parameters come through as undefined
. If you’re in the unenviable position of having to support IE9, there is a polyfill available on MDN.
this
Code executed by setTimeout
is run in a separate execution context to the function from which it was called. This is problematic when the context of the this
keyword is important:
const dog = {
sound: 'woof',
bark() {
console.log(`Rover says ${this.sound}!`);
}
};
dog.bark();
// Outputs: Rover says woof!
setTimeout(dog.bark, 50);
// Outputs: Rover says undefined!
The reason for this output is that, in the first example, this
points to the dog
object, whilst in the second example this
points to the global window
object (which doesn’t have a sound
property).
To counteract this problem, there are various measures …
#javascript #developer