JavaScript timer

1. Introduction

When writing the setTimeout and setInterval code, have you thought about the following points:

  • How did they do it?
  • What would you say if you were asked how you work in an interview?
  • Why do we need to know about timers?

First setTimeout and setInterval are not part of the ECMAScript specification or any JavaScript implementation. It is implemented by browsers and varies from browser to browser. Timers can also be implemented by the Nodejs runtime itself.

In the browser, the timer is an API under the Window object, so it can be called directly from the console.

In Nodejs, timers are part of the Global object, much like Windows in a browser. For details, see the Node-timers source code

Some of you might think, why do we need to understand all this awful, boring stuff when we can just use someone else’s API to develop. I’m sorry to tell you, as a JavaScript developer, I think that if you want to stay a junior developer, you don’t have to, and if you want to improve, you probably don’t fully understand how V8 (and other virtual machines) interact with browsers and Nodes.

This article will use examples to explain JavaScript timers, as well as some interview questions for certain items

2. Some cases of timers

2.1 Delay Cases

// eg1.js
setTimeout(
  () => {
    console.log('Hello after 4 seconds'); }, 4 * 1000);Copy the code

The example above uses setTimeout to print the greeting for 4 seconds. If you execute example1.js in the Node environment. Node will pause for 4 seconds and then print the greeting (and exit).

  • setTimeoutThe first argument function – is the function you want to execute after the expiration time (delay milliseconds).

The first argument to setTimeout is just a function reference. It doesn’t have to be an inline function like eg1.js. Here is the same example without using inline functions:

const func = () => {
  console.log('Hello after 4 seconds');
};
setTimeout(func, 4 * 1000);
Copy the code
  • setTimeoutThe second argument is delay – the number of milliseconds (one second equals 1000 milliseconds) after which the function call will occur. If this parameter is omitted, delay takes the default value 0, which means “immediately” or as soon as possible. In either case, the actual delay time may be longer than the expected value
  • setTimeoutThe third parameter param1… ParamN Optional additional parameters that are passed to function as parameters once the timer expires
/ For: func(arg1, arg2, arg3, ...)
// We can use: setTimeout(func, delay, arg1, arg2, arg3, ...)
Copy the code

Specific examples are as follows:

// example2.js
const rocks = who => {
  console.log(who + ' rocks');
};
setTimeout(rocks, 2 * 1000, 'Node.js');
Copy the code

The rocks above is executed with a 2 second delay, receiving the who argument and passing the string “Node.js” to the function’s who argument via setTimeout. Executing example2.js in the Node environment will print “Node.js rocks” after 2 seconds

2.2 case 2

Using what you have learned so far about setTimeout, print the following two messages after the appropriate delay.

  • Print message “Hello after 4 seconds” after 4 seconds

  • The Hello after 8 seconds message is displayed after 8 seconds.

Note: you can define only one function in the solution, including inline functions. This means that many setTimeout calls must use exactly the same function.

We should soon write something like this:

// solution1.js
const theOneFunc = delay => {
  console.log('Hello after ' + delay + ' seconds');
};
setTimeout(theOneFunc, 4 * 1000, 4);
setTimeout(theOneFunc, 8 * 1000, 8);

Copy the code

TheOneFunc received a delay parameter and used the value of the delay parameter in the printed message. This way, the function can print different messages based on any delay values we pass to it. TheOneFunc is then used in two calls to setTimeout, one after 4 seconds and the other after 8 seconds. The two setTimeout calls also get a third argument to represent theOneFunc’s delay argument.

Executing the solution1.js file using the node command will print out the content required by the challenge, the first message 4 seconds later and the second message 8 seconds later.

2.3 the setInterval case

What if you were asked to print a message every four seconds? While you can put setTimeout in a loop, the timer API also provides a setInterval function, which accomplishes the requirement to do something forever.

// example3.js
setInterval(
  () => console.log('Hello every 4 seconds'), 4000);Copy the code

This example prints a message every 4 seconds. Executing example3.js with the node command will cause Node to print this message forever until you terminate the process.

2.4 Clearing timers

The call to setTimeout returns a timer “ID”, which you can cancel using the timer ID with the clearTimeout call. Here’s an example:

// example4.js
const timerId = setTimeout(
  () => console.log('You will not see this one! '), 0); clearTimeout(timerId);Copy the code

This simple timer should fire after “0” ms (for it to take effect immediately), but it will not cancel immediately because we are capturing the timerId value using the clearTimeout call.

When we execute example4.js with the node command, node does not print anything and the process exits.

By the way, there is another way to perform setTimeout in Node.js using 0 ms. The Node.js timer API has another function called setImmediate, which is basically the same as setTimeout, with 0 ms but we don’t have to specify the delay there:

setImmediate(
  () => console.log('I am equivalent to setTimeout with 0 ms'));Copy the code

The setImmediate method is not supported in all browsers. Don’t use it in front end code.

Just like clearTimeout, there is a clearInterval function that does the same for the setInerval call, as well as a clearImmediate call.

In the previous example, did you notice that executing something with setTimeout after “0” ms does not mean executing it immediately (after the setTimeout line), but immediately after everything else in the script (including the clearTimeout call)? Let me illustrate this point clearly with an example. This is a simple setTimeout call that should fire after half a second, but it won’t:

// example5.js
setTimeout(
  () => console.log('Hello after 0.5 seconds. MAYBE! '), 500);for (let i = 0; i < 1e10; i++) {
  // Block Things Synchronously
}
Copy the code

After the timer is defined in this example, we use a large for loop synchronization to block the runtime. 1e10 is 1 followed by 10 zeros, so the loop is a 10 billion tick loop (basically mimicking a busy CPU). While the loop is ticking, the node cannot do anything.

Very bad thing to do in practice, but it will help you understand that setTimeout delay is not a guaranteed thing, but a minimal thing. 500ms indicates that the minimum delay is 500ms. In fact, the script will take longer to print its greeting. It must wait for the blocking loop to complete.

The node.js Event Loop principle is very deep.

2.4 Print the script and roll out the process

Write a script to print the message “Hello World” every second, but only five times. After five times, the script should print the message “Done” and exit the node process.

You cannot use the setTimeout call to complete this challenge. Tip: You need a counter.

let counter = 0;
const intervalId = setInterval(() => {
  console.log('Hello World');
  counter += 1;
if (counter === 5) {
    console.log('Done'); clearInterval(intervalId); }}, 1000);Copy the code

The counter value is started as 0, and a setInterval call is started and its ID is captured.

The delay function prints the message and increments the counter each time. Inside the delay function, the if statement checks if we are now at 5. If so, it prints “Done” and clears the interval using the captured intervalId constant. The interval delay is “1000” ms.

2.5 When this is combined with timer

When you use JavaScript’s this keyword in regular functions, it looks like this:

function whoCalledMe() {
  console.log('Caller is', this);
}

Copy the code

The value in the this keyword will represent the caller of the function. If the above function is defined in the Node REPL, the caller will be a global object. If you define a function in the browser console, the caller will be a Window object.

Let’s make it clearer by defining functions as properties of objects:

const obj = { 
  id: The '42'.whoCalledMe() {
    console.log('Caller is', this); }}; // Thefunction reference is now: obj.whoCallMe
Copy the code

Now when you call the function obj.whoCallMe directly with its reference, the caller will be the OBj object (identified by its ID)

Now, the question is, if we pass a reference to obj.whoCallMe to the setTimetout call, what will the caller be?

//  What will this print??
setTimeout(obj.whoCalledMe, 0);
Copy the code

Who would be the caller in this case?

The answer varies depending on where the timer function is executed. In this case, you can’t depend on who the caller is. You lose control of the caller, because the timer implementation will be the implementation of the function that now calls you. If you test it in the Node REPL, you will get a Timetout object as the caller

Note that this only makes sense if you use JavaScript’s this keyword in regular functions. If you use arrow functions, you don’t need to worry about the caller at all.

2.6 Continuously Printing The Message “Hello World” with Different Delays

Start with a delay of 1 second, then increase the delay by 1 second each time. The second delay will be 2 seconds. The third time will be delayed by 3 seconds, and so on.

Include the delay time in the printed message. The expected output would look like:

Hello World. 1
Hello World. 2
Hello World. 3...
Copy the code

You can only define variables using const. You can’t use let or var. Let’s start with the following analysis:

  • Since the amount of latency is a variable in this challenge, we cannot use it heresetInterval, but we can use it in recursive callssetTimeoutManually create an interval execution. usesetTimeoutThe first executing function of “will create another timer, and so on.
  • Also, since we cannot use let/var, we cannot have a counter to increase the delay time for each recursive call, but we can use recursive function arguments to increase during recursive calls.

Here’s one way to solve the problem:

const greeting = delay =>
  setTimeout(() => {
    console.log('Hello World. ' + delay);
    greeting(delay + 1);
  }, delay * 1000);
greeting(1);
Copy the code

Write a script to print the message “Hello World” consecutively, with the same concept of variation delay as challenge # 3, but this time with five message groups per main delay interval. Start with a 100ms delay for the first five messages, then 200ms for the next five messages, then 300ms, and so on.

Here are the code requirements:

  • At the 100ms point, the script will start printing “Hello World” five times at 100ms intervals. The first message will appear in 100 milliseconds, the second in 200 milliseconds, and so on.

  • After the first five messages, the script should increase the main delay to 200ms. Therefore, the sixth message will print at 500 ms + 200 ms (700 ms), the seventh message will print at 900 ms, the eighth message will print at 1100 ms, and so on.

  • After 10 messages, the script should increase the main delay to 300 milliseconds. So the 11th message should be printed at 500ms + 1000ms + 300ms (18000ms). The 12th message should be printed at 21000ms, and so on.

Keep repeating the above pattern.

Hello World. 100  // At 100ms
Hello World. 100  // At 200ms
Hello World. 100  // At 300ms
Hello World. 100  // At 400ms
Hello World. 100  // At 500ms
Hello World. 200  // At 700ms
Hello World. 200  // At 900ms
Hello World. 200  // At 1100ms...
Copy the code

You can only use setInterval calls (not setTimeout), and only one if statement.

Here’s one solution

let lastIntervalId, counter = 5;
const greeting = delay => {
  if (counter === 5) {
    clearInterval(lastIntervalId);
    lastIntervalId = setInterval(() => {
      console.log('Hello World. ', delay);
      greeting(delay + 100);
    }, delay);
    counter = 0;
  }
counter += 1;
};
greeting(100);

Copy the code

3. A timer during an interview

3.1 something – Implement a repeat method with JS

Implement a repeat method with JS with the following input and output: // implementationfunction repeat (func, times.wait}, // enter const repeatFunc = repeat(alert, 4, 3000); // Call this repeatedFunc ("hellworld"), will alert4 helloworld times, each interval of 3 secondsCopy the code

One solution is as follows

function repeat(func, times.wait) {
    return function () {       
        let timer = null
        const args = arguments
        let i = 0;
        timer = setInterval(()=>{
            while (i >= times) {
                clearInterval(timer)
                return
            } 
            i++
            func.apply(null, args)
        }, wait)}}Copy the code

3.2 a certain – please implement JS throttle function

Function throttling interpretation: Adds a layer of control over function execution to ensure that it is executed only once in a (configurable) period of time. This function is used to control the frequency of function execution and is often used in scenarios where the user fires frequently but can respond at a lower frequency

One solution:

function debounce (fn, time) {
   let first = true
   let timer = null
    return function(... args) {if (first) {
           first = false
            fn.apply(this, args)
            
        }
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, 100)
    }
}

Copy the code

Thanks for reading and welcome to continue

reference

  • JavaScript Timers: Everything you need to know
  • timer-functions