JS - 03.07 - Scheduling

Scheduling Function Calls with setTimeout and setInterval

JavaScript provides the ability to schedule functions to be executed later or repeatedly using two methods: setTimeout and setInterval.

  • setTimeout allows us to run a function once after the interval of time.

  • setInterval allows us to run a function repeatedly, starting after the interval of time, then repeating continuously at that interval.


setTimeout( )

The setTimeout() method allows you to schedule a function to run once after a specified delay.

let timerId = setTimeout(func|code, delay, [arg1], [arg2], ...);
  • func|code: Function or string of code to execute after the delay. Usually it’s a function.
  • delay: The time to wait (in milliseconds) before executing the function. The default is 0 (run immediately) (1000 ms = 1 second).
  • arg1, arg2, …: Arguments to pass to the function when it executes (optional).
function sayHi() {
  alert('Hello');
}

setTimeout(sayHi, 1000);  // Executes sayHi after 1 second (1000 ms)

You can pass arguments to the function using setTimeout.

function sayHi(phrase, who) {
  alert(phrase + ', ' + who);
}

setTimeout(sayHi, 1000, "Hello", "John"); // "Hello, John"

Here, sayHi is called with "Hello" and "John" after 1 second.

If the first argument is a string, the js creates a function from it.

Using Arrow Functions (Best Practice):

It’s better to use arrow functions rather than passing a string of code:

setTimeout(() => alert('Hello'), 1000);

Passing a string is not recommended because it has security and performance issues. It is safer and clearer to use a function or an arrow function.

Common Mistake (Calling Function Immediately):

When you call the function immediately, it doesn’t work as expected. You need to pass the function reference, not the result of its execution.

setTimeout(sayHi(), 1000);  // WRONG! sayHi is executed immediately

// Correct way:
setTimeout(sayHi, 1000);  // Pass the function reference, don't call it

setTimeout expects a reference to a function. And here sayHi() runs the function, and the result of its execution is passed to setTimeout.

In the wrong example, sayHi() is executed immediately, and its return value (which is undefined) is passed to setTimeout. You should pass sayHi without parentheses to ensure it is executed later.


clearTimeout( )

You can cancel a scheduled setTimeout() function before it executes by using clearTimeout().

clearTimeout(timerId);
  • timerId is the identifier returned by setTimeout.
let timerId = setTimeout(() => alert("never happens"), 1000);

clearTimeout(timerId);  // This cancels the timeout before it executes

Even though clearTimeout(timerId) is called, the alert will never show because the execution was canceled.


setInterval( )

The setInterval() method is similar to setTimeout, but it runs the function repeatedly at the specified interval.

let timerId = setInterval(func, delay, [arg1], [arg2], ...);
  • func: The function to execute repeatedly.
  • delay: The time (in milliseconds) between each execution of the function.
  • arg1, arg2, …: Arguments to pass to the function (optional).
let timerId = setInterval(() => alert('tick'), 2000);  // Alerts "tick" every 2 seconds

Stopping the Interval:

You can stop the interval by calling clearInterval() and passing the timerId returned by setInterval.

let timerId = setInterval(() => alert('tick'), 2000);

setTimeout(() => {
  clearInterval(timerId);  // Stops the interval after 5 seconds
  alert('stop');
}, 5000);
  • The "tick" alert happens every 2 seconds.
  • After 5 seconds, the interval is cleared, and "stop" is shown.

Behavior in Browsers:

  • In most browsers, including Chrome and Firefox, the internal timer continues to run even when a modal window (alert, confirm, etc.) is open.
  • So, if you don’t dismiss the alert for a while, the next "tick" will be shown immediately after you close the current one, making the interval appear shorter.

Nested setTimeout()

Nested setTimeout

You can schedule the next function call within the function itself, creating a loop that behaves similarly to setInterval(), but with more flexibility.

let timerId = setTimeout(function tick() {
  alert('tick');
  timerId = setTimeout(tick, 2000);  // Schedules the next tick after 2 seconds
}, 2000);

This method allows you to control when the next function is called based on the results of the current execution. For example, you might want to vary the interval or conditionally stop the execution.

The key difference is that with setInterval, the next interval is always scheduled immediately, but with nested setTimeout, you can choose to delay the next call further or conditionally stop it based on some logic.


Important Notes on setTimeout and setInterval:

  1. Timers are not guaranteed to be precise. The delay is the minimum time before execution, and the actual execution might happen later due to factors like system load, other running scripts, or the browser’s event loop.

  2. Avoid using setTimeout and setInterval for high-precision tasks. For tasks that require high precision (like animations or real-time operations), it’s better to use requestAnimationFrame or other appropriate APIs.

  3. Memory leaks can occur. If intervals or timeouts are not cleared properly, they can continue to run in the background, consuming memory and resources.


Summary

  • setTimeout(func, delay) runs func once after delay milliseconds.
  • setInterval(func, delay) runs func repeatedly every delay milliseconds.
  • Use clearTimeout(timerId) or clearInterval(timerId) to stop a scheduled timeout or interval.
  • Nested setTimeout() provides more flexibility over setInterval() and can help in cases where you need to control the timing more precisely.