This is the fifth day of my participation in the August Wen Challenge.More challenges in August

The reasons causing

Due to js EventLoop execution mechanism, setTimeout/setInterval only inserts the event into the task queue, and the main thread will execute its specified callback function only after the current code (execution stack) completes execution. If the current code takes a long time, it may wait a long time, so there is no guarantee that the callback will be executed at setTimeout(). Therefore, the actual time to wait for execution = the time to wait for the execution stack to be empty + the set delay callback time, then the time deviation is generated, that is, the time deviation = the time to wait for the execution stack to be empty.

SetTimeout (fn,0) specifies that a task should be executed at the earliest available idle time on the main thread, i.e. as early as possible. It adds an event to the end of the task queue so that it does not execute until both the synchronization task and the existing events in the task queue have been processed, rather than immediately executing at a preset callback time of 0.

The solution

Methods a

The backend sends a request to the server periodically to obtain the latest time deviation and calibrate the countdown time. However, this method consumes a lot of server resources and has concurrency problems. Moreover, the interface request return time itself also has time deviation, which increases the uncontrollable factors and complexity of the problem

Method 2

In each recursive call of setTimeout callback, calculate the time deviation. In the next execution of setTimeout, subtract the time deviation from the original set delay callback time.

    const interval = 1000 // Set the countdown rule to count down every second
    let totalCount = 30000 // Set the total countdown length to 30s
    let count = 0 // Count the number of times the recursion has been executed. Take the countdown interval=1s as an example, then count is the ideal execution time if there is no time deviation
    
    const startTime = new Date().getTime(); // Record the start time of the program
    let timeoutID = setTimeout(countDownFn, interval)
    
    // Countdown callback function
    function countDownFn() {
        count++ // count is incremented to record the desired execution time
        // Get the current time minus the startTime originally recorded and minus the ideal execution time to get the time deviation: the time to wait for the execution stack to be empty
        const offset = new Date().getTime() - startTime - count * interval
        let nextTime = interval - offset // According to the time deviation, calculate the callback time set by the next countdown, so as to achieve the purpose of correction
        if (nextTime < 0 ) {
            nextTime = 0
        }
        totalCount -= interval
        if (totalCount < 0) {
            clearTimeout(timeoutID)
        } else {
            timeoutID = setTimeout(countDownStart, nextTime)
        }
    }
Copy the code

reference

Nguyen other Eventloop