Timed Events in Javascript
There are ways in javascript to create a timed sequence of actions, either through delaying or by setting a repeated interval. In this tutorial, we will look at two functions of the BOM window object: setInterval() and setTimeout(). Before looking specificially into these functions, we will need to know the concept of "callback functions".
Callback Functions
Callback function is a function that is used as an argument of another function. We know that a function can take "arguments" or inputs that is passed to be used inside of the function, for example:
function timesTwo(number){ var total = number * 2; console.log(total); }
Instead of giving a variable as an argument of a function, you can give a function as an argument of another function like this:
function getNumber(callback){ var number = prompt("Give me a number, and I'll multiply it by two."); callback(number); } function timesTwo(number){ var total = number * 2; console.log(total); } getNumber(timesTwo);
In the example above, timesTwo function is given as an argument of the getNumber function. The timesTwo function is used inside of the getNumber function after the number is received from the prompt window.
We've actually been using callback functions without realizing. The functions we give as values of our events, such as onclick, onmouseover and onmouseout, are actually callback functions. It is because the onclick attributes of html elements are actually a way of adding an "event listener" to a particular html element. For example, if we have a <div> element that has an onclick attribute like this:
<div id="divId" onclick="clickFunction()"></div>
This could actually be written purely in javascript as:
document.getElementById("divId").addEventListener("click", clickFunction);
In the case above, clickFunction is a callback function of the addEventListener function.
Similar to the addEventListener function, both setInterval() and setTimeout() takes a function as an argument.
setInterval()
setInterval() function is used to do a set of actions EVERY INTERVAL of the specified time. This function takes two arguments:
setInterval(callback, time);
The first argument of the function is a callback function, used to specify the set of action you would like to do for every specified time. For example:
setInterval(changeBackground, 1000);
In the example above, the changeBackground function is given as a callback function of the setInterval function to run every 1000 milliseconds (= 1 second). Another way of using setInterval() without defining a specific function to pass in as an argument would be:
setInterval(function(){ //code here for changing background }, 1000);
setTimeout()
setTimeout() function is used to do a set of actions AFTER the specified time. It takes two argument, just like the setInterval function.
setTimeout(callback, time);
For example, if we have a line of code that looks like below:
setTimeout(changeBackground, 5000);
it means that the changeBackground function will run every 5000 milliseconds (= 5 seconds).
But what if you need to pass in arguments inside of the changeBackground function? For example, if our changeBackground function looks like below:
function changeBackground(color){ document.getElementById("divId").style.backgroundColor = color; }
to be able to use this function inside, we will also want to give an argument of the changeBackground function inside of setTimeout(). Logically, you would think that the below code will work.
setTimeout(changeBackground("red"), 5000);
Above will not work, because the syntax of the setTimeout function is that the first argument has to be a NAME of a function. changeBackground("red") is a function call, not a name of a function, meaning that when it is written this way in javascript, it will execute the changeBackground function with "red" as argument, as soon as the javascript file is loaded. Which is why if were to put the above line of code inside of our javascript file, it will actually change the background-color of the <div> of id "divId" WITHOUT waiting for the 5000 second given as the specified time of delay.
Let's look at a demo of how the setTimeout() and setInterval() functions could be used.
Click to view the demo as a full web page.
Below is the full code of the demo:
HTML:
<body> <div id="counter"><span id="counter-text">5</span<</div> </body>
CSS:
body, html{ margin: 0; height: 100%; background-color: white; } .box{ display: inline-block; } .box:hover{ opacity: 0.5; } #counter{ position: absolute; top: calc(50% - 24px); left: calc(50% - 12px); font-size: 48px; }
JAVASCRIPT:
var divs = []; var windows = []; window.onload = function(){ for(var i = 0; i < 9; i++){ windows[i] = i + ".html"; var newDiv = document.createElement('DIV'); newDiv.id = i; newDiv.className = "box"; newDiv.style.width = "30%"; newDiv.style.height = "30%"; newDiv.style.marginLeft = "2.5%"; var mTop = window.innerHeight * 0.025; newDiv.style.marginTop = mTop + "px"; newDiv.style.backgroundColor = "rgb(" + Math.floor(Math.random() * 255) + ", " + Math.floor(Math.random() * 255) + ", " + Math.floor(Math.random() * 255) + ")"; newDiv.setAttribute("onclick", "popupWindow(" + i + ")"); document.body.appendChild(newDiv); } divs = document.getElementsByClassName('box'); setInterval(changeBackground, 5000); setInterval(increaseCounter, 1000); } var counter = 5; function increaseCounter(){ counter--; if(counter == 0){ counter = 5; } document.getElementById('counter-text').innerHTML = counter; } function changeBackground(){ for(var i = 0; i < divs.length; i++){ divs[i].style.backgroundColor = "rgb(" + Math.floor(Math.random() * 255) + ", " + Math.floor(Math.random() * 255) + ", " + Math.floor(Math.random() * 255) + ")"; } } function popupWindow(i){ // var newWindow = window.open("js-timed-events/" + windows[i], "_blank", "width=640, height=480, left=400, top=200"); var newWindow = window.open("", "_blank", "width=640, height=480, left=400, top=200"); var textCol = divs[i].style.backgroundColor; newWindow.document.write('<h1 style="color:' + textCol + '">Window ' + i + '</h1>'); setTimeout(function(){ newWindow.close(); }, 2000); }