In this lesson we discuss
Date.now()
setTimeout
and setInterval
Ironically, the normal way to tell the time in JavaScript is to use an object called Date.
Calling Date.now()
returns a very big number... try it now.
That number represents the number of milliseconds that have elapsed since January 1, 1970.
This value is also known as unix time or epoch time, and is a standard way of marking time in software... although as usual, JavaScript is not quite following the standards, since usually it's expressed in seconds, not milliseconds.
As a really quick exercise, calculate the number of months since 1970.
Hint: remember the Playing With Numbers lab?
The concept of callbacks is very common in JavaScript. In fact, you've probably used them already!
In this lesson we will focus on callbacks in the context of another very useful and common function, setTimeout
.
A callback is just a function.
What makes it special is that you pass in as a parameter to a different function.
Later on, the callback function gets called back -- but not by your own code.
Rather, the function that you passed it in to in the first place either calls it immediately, or stores it away somewhere, so that it can be called when something else happens later on...
...possibly seconds or minutes or hours later!
The built-in function setTimeout
sets up a callback.
You call it with two parameters:
setTimeout
returns immediately, but also sets up a hidden timer
after approximately N milliseconds, F gets called back
Try this now:
function later() {
console.log("See you later...");
setTimeout( alligator, 1000 );
}
function alligator() {
console.log("Alligator!")
}
later();
This "later alligator" program could be rewritten to use an anonymous inline function instead of a named top-level function.
function later() {
setTimeout( function() {
console.log("Alligator!")
}, 1000 );
console.log("See you later...");
}
later();
Using inline callbacks is a very common idiom in JavaScript, especially with setTimeout
.
The syntax can be confusing because of all the parentheses and curly braces, but it's essentially the same pattern as above:
setTimeout
with two parameterssetTimeout
will return immediately, then wait 1000 msec, then call the functionNote that even though "See you later" appears lower in the code than "Alligator", it happens first because
setTimeout
returns immediately.
Let's zoom in on the call to setTimeout
.
setTimeout( function() {
console.log("Alligator!")
}, 1000 );
add(2, 2)
.function() { console.log("Alligator!") }
The comma separating the parameters comes immediately after the inline function's closing brace:
"Alligator!") } , 1000
--------------/ | \---/
| | |
first arg | second arg
comma
Fat arrows can make inline function code more concise, and (to some) clearer. YMMV!
setTimeout( () => console.log("Alligator!") , 1000 );
In this lab, we will demonstrate that setTimeout
is not perfect.
(But hey, who is?)
Write a function named waitASecond
that...
setTimeout
to set up a one second timerNow run the function several times in a row. What do you notice?
Click Here for Solution
function waitASecond() {
let start = Date.now();
setTimeout(
function() {
let end = Date.now();
console.log(end - start);
},
1000)
}
setTimeout
has a sibling named setInterval
It works a lot like setTimeout
but is a little more complicated.
After calling setInterval
, JavaScript will call your callback again and again forever until you clear the timer.
For example:
function countDownFrom(num) {
let intervalId = setInterval(tick, 1000);
function tick() {
console.log(num);
num = num - 1;
if (num <= 0) {
console.log('Blastoff!');
clearInterval(intervalId);
}
}
}
countDownFrom(10);
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval
When you want something to happen again and again on a fixed delay, you need to choose between setInterval
and setTimeout
.
setInterval
is a bit more powerful but also a bit more complicated.
Note that anything you do with setInterval
could instead be implemented using setTimeout
, as long as your callback calls setTimeout
again recursively, like this:
function countDownFrom(num) {
setTimeout(tick, 1000);
function tick() {
console.log(num);
num = num - 1;
if (num <= 0) {
console.log('Blastoff!');
} else {
setTimeout(tick, 1000);
}
}
}
countDownFrom(10);
This design decision comes down to personal style and preference; the two solutions have about the same complexity and number of lines of code.
Use a "Mock Clock"
setTimeout
with a different function during testsIn Jasmine:
beforeEach(function() {
jasmine.Clock.useMock();
});
//... call the code that calls setTimeout
jasmine.Clock.tick(500); // advance 500 msec
/