First, an interview question caused by the thinking

Some day go to work to touch fish, someone in a Q group is sending pen test questions online help. I had a cursory glance. I found a subjective judgment question in it.

The code says setInterval(()=>{console.log(‘a’)},10000), which must print an A on the console every 10 seconds.

Maybe a lot of people at first impression, including me, think this is right. But it’s wrong!!

Why? It’s the JavaScript execution mechanism. If you don’t know what JavaScript execution mechanism is, you can click here.

Definition and usage of setTimeout

1. Definition of setTimeout

The setTimeout() method is used to call a function or evaluate an expression after a specified number of milliseconds.

2. SetTimeout parameters

  • The first argument function, mandatory, can be a function or a function name.

  • The second parameter delay, optional, is the delay time in ms.

  • The third parameter param1,param2,param3… Optionally, the argument passed to the callback function is less commonly used and is not supported in IE9 and earlier versions.

    setTimeout(function(a) {
    	console.log(a);
    }, 2000,'I'm the timer.')
    Copy the code
    setTimeout(foo, 2000,'I'm the timer.')
    function foo(a){
        console.log(a)
    }
    Copy the code

3. Return value of setTimeout

Returns an ID (number) that can be passed to clearTimeout() to cancel execution.

Definition and usage of setInterval

1. Definition of setInterval

The setInterval() method calls a function or evaluates an expression at a specified period in milliseconds.

2. SetInterval parameters

  • The first argument function, mandatory, can be a function or a function name.
  • The second parameter, delay, is an optional interval in ms.
  • The third parameter param1,param2,param3… Optionally, the argument passed to the callback function is less commonly used and is not supported in IE9 and earlier versions.
    setInterval(function(a) {
    	console.log(a);
    }, 2000,'I'm the timer.')
    Copy the code
    setInterval(foo, 2000,'I'm the timer.')
    function foo(a){
        console.log(a)
    }
    Copy the code

3. Return value of setInterval

Returns an ID (number) that can be passed to clearInterval() to cancel execution.

SetTimeout Specifies the minimum delay time

When the second delay parameter is not set, it defaults to 0, meaning “immediately” or as soon as possible.

But one rule is as follows

If timeout is less than 0, then set timeout to 0. If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.

If the delay is less than 0, set the delay to 0. If the nesting level is greater than 5 and the delay is less than 4ms, set the delay to 4ms.

There’s another situation. To save power, the browser extends the minimum latency limit to 1000ms for pages not in the current window.

The above can be said to be one of the reasons for the timing is not accurate

5. SetInterval Specifies the minimum interval

In John Resig’s new book, Javascript Ninja Secrets

Browsers all have a 10ms minimum delay on OSX and a(approximately) 15ms delay on Windows.

The minimum interval is 10 milliseconds on a MAC and about 15 milliseconds on Windows.

Most computer monitors refresh at 60 Hz, which equates to about 60 redraws per second. Therefore, the optimal cycle interval for the smoothest animation effect is 1000ms/60, which is approximately 16.6ms.

To sum up, I think the minimum interval for setInterval should be 16.6ms.

SetTimeout and setInterval

In either case, the actual delay time may be longer than the expected value.

In addition to setting the delay is shorter than the minimum delay time and the minimum interval time, there is another reason is caused by the JavaScript execution mechanism, the following uses an example to analyze.

<body>
    <button id="btn"></button>
    <script>
        const btn = document.getElementById("btn");
        btn.addEventListener('click'.function handleClick() {/ /... Code execution time: 80ms})setTimeout(function handlerTimeout() {/ /... Code execution time is 60ms}, 100);setInterval(function handlerInterval() {/ /... },100) //... The rest of the code takes 180ms </script> </body>Copy the code

We use a timeline to describe how the code executes.

At 100ms, the two timers are supposed to complete at the same time, but the setTimeout timer is written first, so its callback function handlerTimeout enters the event queue first. The callback function handlerInterval is executed after it enters the event queue.

But in reality, the handlerTimeout callback can only be executed at 180ms because the rest of the code takes 180ms to execute, meaning that the main thread is idle until 180ms. The handlerInterval callback needs to wait until the handlerTimeout callback has finished executing, or at 240ms.

The real reason for the above phenomenon can be seen in my other article how JavaScript is executed 🔥

Therefore, it can be concluded that setTimeout and setInterval cannot guarantee the punctual execution of callback functions.

Deprecated setInterval callbacks

At 200ms, setInterval runs out again, and the callback handlerInterval returns to the event queue.

The answer is no, because the event queue already has a callback function called handlerInterval.

The setInterval callback is deprecated.

SetInterval Specifies the execution time of the callback function

At 240ms, the handlerTimeout callback ends and the handlerInterval callback begins.

At 300ms, setInterval runs out again and handlerInterval is no longer in the event queue. The callback function handlerInterval is then queued for events.

At 320ms, the last callback, handlerTimeout, completes, and the next callback, handlerTimeout, immediately follows.

At 400ms, setInterval runs out again and handlerInterval is no longer in the event queue. The callback function handlerInterval is then queued for events. Just as the last callback handlerTimeout completes, the next callback handlerTimeout will immediately follow.

You will notice that the callback handlerTimeout executes with no interval, and the interval is gone.

So setInterval must be longer than the callback.

However, in many cases, we do not clearly know the execution time of the callback function. In order to trigger the timer periodically at a certain interval, we can use the following methods to achieve.

setTimeout(function handlerInterval() {/ /do something
    setTimeout(handlerInterval,100); // After executing the contents of the handler, call the program at the end of the 100 ms interval, so that it is guaranteed to be 100 ms cycle},100)Copy the code

However, there is a time error in this method. We need to optimize it

function mySetInterval(timeout) {
    const startTime = new Date().getTime();
    let countIndex = 1;
    let onOff=true;
    startSetInterval(timeout)
    function startSetInterval(interval) {
        setTimeout(() => { const endTime = new Date().getTime(); // Const deviation = endTime - (startTime + countIndex * timeout); console.log(`${countIndex}Deviation:${deviation}ms`); countIndex++; / / the nextif(onOff){
                startSetInterval(timeout - deviation);
            }
        }, interval);
    }
    
    function stopSetInterval(){
        onOff=false;
    }
    return stopSetInterval
}
Copy the code