preface

I am writing this article because I encountered some problems last week when I used setInterval to poll the request interface

Get into the business

SetTimeout and setInteval are the two main timing methods on window objects. Their syntax is basically the same, but they perform different functions.
  • The setTimeout method is a timer program that executes something after a specified time. (Execute once and pull down)
  • The setInterval method is to do something over and over again at a certain amount of time.
Return value of the timer
  • When we set a timer (either setTimeout or setInterval), there is a return value. The return value is a number representing the current timer set in the browser (the timer number is returned).
      let timer1 = setTimeout((a)= >{},1000)
      console.log(timer1) / / 1
    
      let timer2 = setInterval((a)= >{},1000)
      console.log(timer2) / / 2
    Copy the code
    • According to the above two pieces of code can know
      • 1. SetTimeout and setInterval are different timers, but they are both browser timers, so the sequence number returned is in order.
      • 2. SetInterval sets the completion timer to have a return value. No matter how many times the timer is executed, the return value represents the sequence number.
Timer clearance
  • ClearTimeout ([queue number of timer])

  • ClearInterval ([queue number of timer])

      let timer = setTimeout((a)= > {
        // The return value of the timer will not be cleared even if it is cleared, and the return value of the timer will be added to the return value of the timer.
        // It is similar to the queue number of the bank. Even after the business of number 1 is completed, the people behind will continue to get the number from number 2, instead of starting from number 1.
        clearTimeout(timer)
      }, 1000)
    Copy the code

Note: Timers need to be manually cleared, and both clearTimeout and clearInterval can clear setTimeout or setInterval, but this is not recommended because it can cause confusion.

The this point of the timer
  • The function that takes the first argument will be executed at the global scope, so this inside the function will point to the global object
      let obj = {
        fn() {
          console.log(this) // obj
    
          / / sample 1
          let timer1 = setTimeout(function() {
          
            console.log('I'm timer1's this points to :'.this)  // Window
          }, 1000)
    
          // Example 2 (let this be obj in the timer function: use variable save mode)
          let _this = this
          let timer2 = setTimeout(function() {
            console.log('I'm timer2's this points to :', _this) // obj
          }, 1000)
    
          // Example 3 (make this obj in the timer function: use bind to change this pointer)
          let timer3 = setTimeout(
            function() {
              console.log('I'm timer3's this points to :'.this) // obj
            }.bind(this),
            1000
          )
    
          // Example 4 (make this obj in the timer function: use the arrow function, which inherits from the host environment (this in the parent scope))
          let timer4 = setTimeout((a)= > {
            console.log('I'm timer4 this points to :'.this) // obj
          }, 1000)
        }
      }
      obj.fn()
    Copy the code

How do setTimeout and setInterval work?

JS EVENTLOOP mechanism EVENTLOOP

  • First, Javascript is a single-threaded, non-blocking scripting language: used to interact with browsers.
    • Single thread: Only one task can be executed at a time. Other tasks must be queued and subsequent tasks must wait until the previous task is finished.
    • Non-blocking: Synchronous tasks execute directly and sequentially on the main thread queue, while asynchronous tasks enter another task queue without blocking the main thread. Wait until the main thread queue is empty (performed), will go to asynchronous queue whether there is an executable query of the asynchronous task (asynchronous tasks usually after entering the asynchronous queue have to wait to perform some conditions, such as ajax requests, read and write files), if an asynchronous task can perform the joins in the main thread queue, this cycle.

Note: Asynchronous tasks are not the same and have different execution priorities. There are two types of asynchronous tasks: Micro tasks and Macro tasks.

  • Microtasks: New Promise (), new MutaionObserver()
  • Macro task: setInterval(), setTimeout() when the main thread is idle, it will first check whether there are events in the microtask queue. If there are, it will call the events in the microtask queue until it is empty. Then execute the macro task queue in turn to enter the loop.

When using timers, do not trust expectations. The lag time is always more than XXX milliseconds, depending on the execution at the time. Even if it is set to 0, it does not execute immediately. HTM5 specifies that the minimum latency should not be less than 4ms. Implementations vary from browser to browser. For example, Chrome can set it to 1ms and IE11/Edge to 4ms.

setTimeout

The function fn registered by setTimeout will be administered by the browser timer module. When the delay is over, fn will be queued for execution by the main process. If there is still unfinished code in the queue, it will take a little longer to execute fn, so the actual delay will be longer than the set time. If there is a super loop right before fn, the delay time is not a tiny bit.

(function testSetTimeout() {
    console.time('timer');
    const timer = setTimeout((a)= > {
        console.timeEnd('timer');
    }, 10);
    for(let i = 0; i < 100000000; i++) {}
})();

// timer: 59.364990234375ms
Copy the code
setInterval

Why try not to use setInterval??

SetInterval ignores code errors

SetInterval has a nasty habit of not caring if the code it is calling is wrong, and if the code it is executing is wrong for some reason, it will keep calling that code (regardless).

function a() {
  try {
    cnosole.log('Misspelled word, it should be console.')}catch (e) {
    console.log('Wrong')
  }
}
setInterval(a, 1000)

// 8VM69:5 error (console output an error every second)
Copy the code
SetInterval ignores network latency

Suppose you poll the server every once in a while using Ajax to see if there is any new data. For some reason (server overloads, temporary outages, traffic surges, limited user bandwidth, etc.), your request may take longer than you think. But setInterval doesn’t care. It will still trigger requests continuously and regularly, and eventually your client network queue will be stuffed with Ajax calls.

Example: the following code does not start the next fn 100ms after the last fn execution. In fact, setInterval does not care about the result of the last FN execution, but instead puts the FN in an asynchronous queue every 100ms. The exact interval between the two fn’s is uncertain, similar to the actual delay of setTimeout, which depends on the JS execution.

(function testSetInterval() {
    let i = 0;
    const start = Date.now();
    const timer = setInterval((a)= > {
        i++;
        i === 2 && clearInterval(timer);
        console.log(The first `${i}Began `.Date.now() - start);
        for(let i = 0; i < 900000000; i++) {}
        console.log(The first `${i}Time end `.Date.now() - start);
    }, 100); }) (); VM232:71Time began104
VM232:91End of the time603
VM232:72Time began605
VM232:92End of the time1106
Copy the code

Although each fn execution takes a long time, the next one is not executed 100ms after the last one, it is actually already in the queue. While fn is blocked, setInterval is still organizing future calls to the callback function. Thus, by the time the first fn call ends, there are already six function calls waiting to be executed.

Handle possible blocking calls

The simplest and most manageable solution is to use the setTimeout function inside the callback function.

function foo(){
    setTimeout(foo, 100);
}
foo();
Copy the code
Refer to the link
  • Mp.weixin.qq.com/s/Wsa-aXGYA…