JS - setTimeout time error solution

JS - setTimeout time error solution

1. Background

Recently, a timer was added to the project. I used setTimeout to realize the timing to display the remaining payment time of the order, but I found that the short time is fine, but if the time is long, the error of the timer will be large.

Two, the problem
  1. Timing with setTimeout
var start = new Date().getTime() 
var count = 0 // 程序执行了秒数 增加
var inits = 1000 // 间隔时间
var timer = setTimeout(fun,inits)
console.log("start",start);
function fun(){
    
    
 	count ++
    // 当前时间 - (开始时间+过程时间) => 如果为0,没有误差;大于0,有误差
    var errorTime = new Date().getTime() - (start + count*1000) + "ms"
    console.log(errorTime);
    if(count < 10){
    
    
      	timer = setTimeout(fun,inits)
    }
}

insert image description here

3. Analysis

There will be errors in the implementation of setInterval and setTimeout, which stems from the single thread of js.
Their callback function is not executed immediately after the time, but will be executed after the system computing resources are free.
Both setInterval and setTimeout are macro tasks.

4. Simulate blocking events

Now let's simulate it, add some code that blocks the thread and try

// 阻塞代码
setInterval(function(){
    
    
    var n = 0
    while(n++ <= 1000000000);
},1000)

var start = new Date().getTime() 
var count = 0 // 程序执行了秒数 增加
var inits = 1000 // 间隔时间
var timer = setTimeout(fun,inits)
console.log("start",start);
function fun(){
    
    
 	count ++
    // 当前时间 - (开始时间+过程时间) => 如果为0,没有误差;大于0,有误差
    var errorTime = new Date().getTime() - (start + count*1000) + "ms"
    console.log(errorTime);
    if(count < 10){
    
    
      	timer = setTimeout(fun,inits)
    }
}

insert image description here

It can be seen that after adding some codes that block threads, the error becomes more and more serious.
In actual projects, while executing the timer, there will be many other asynchronous blocking events, which will cause the countdown function to be inaccurate.

5. Solutions

We need to perform error correction, that is, to obtain the value of the error, and dynamically adjust the interval time for our execution of the callback according to the error value

  1. Calculate the error value
  2. Dynamically adjust the interval of executing setTimeout
var start = new Date().getTime()
var count = 0
var inits = 1000
var offset = 0;//误差时间
var nextTime = inits - offset;//原本间隔时间 - 误差时间
var timer = setTimeout(doFunc,nextTime);
function doFunc(){
    
    
    count++
    console.log(new Date().getTime() - (start + count * inits) + 'ms');
    offset = new Date().getTime() - (start + count * inits);
    nextTime = inits - offset;
    if (nextTime < 0) {
    
     nextTime = 0; }
    if(count < 10){
    
    
        timer = setTimeout(doFunc,nextTime);
        console.log("nextTime",nextTime);
    }
}

insert image description here
It can be seen that each nextTime will be dynamically adjusted according to the last error value to minimize the overall error.

Guess you like

Origin blog.csdn.net/weixin_42365757/article/details/123802004