前端倒计时不精准?试试这个

425 阅读1分钟
  • 个人博客:kirk.wang/

  • 解决什么问题? 使用new Date()方式实现的倒计时会受到系统时间的影响,比如修改系统时间,就可以修改倒计时的时间。

  • perfromance.now是什么?

  • 在JavaScript中,perfromance.now()方法可用于检查代码的性能。您可以使用此方法检查代码的执行时间。

它返回以毫秒为单位的时间值(double类型)。返回的值表示自执行开始以来经过的时间。 用法:

let t = performance.now();

下面的代码将使您对该代码的执行方式有一个简短的了解。

范例1:

<script> 
  const t0 = performance.now(); 
  for (let i = 0; i < 10; i++) { 
    console.log(i); 
  } 
  const t1 = performance.now(); 
  console.log(`Call to doSomething took ${t1 - t0} milliseconds.`); 
</script>
  • 根据这个特性,我们可以使用performance.now 实现不受系统时间影响的倒计时 先看效果图 效果图 以下是完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body style="width:100vw;padding-top: 100px;">
    <div>
        <div style="display: flex;justify-content: center;flex-direction: column; align-items: center;">
            <div class="title">倒计时1-服务器时间</div>
            <div class="currentTime"></div>
            <div><button class="stopBtn">stop</button>
                <button class="pauseBtn">pause</button>
            </div>
        </div>
        <br>
        </br>
        <div style="display: flex;justify-content: center;flex-direction: column; align-items: center;">
            <div class="title">倒计时2-毫秒数倒计时</div>
            <div class="currentTime2"></div>
            <div><button class="stopBtn2">stop</button>
                <button class="pauseBtn2">pause</button>
            </div>
        </div>

    </div>

    <script>
        (async () => {
            var localStartTime;
            var ServeTime = await getServerTime()
            var ServeEndTime = await getServerEndTime()
            // 服务器当前时间
            function getCurrentServeTime() {
                return ServeTime + (performance.now() - localStartTime)
            }
            // 服务器剩余时间数
            async function getTime() {
                return ServeEndTime - getCurrentServeTime()
            }
            // 毫秒转天时分秒
            function formatDuring(mss) {
                var days = parseInt(mss / (1000 * 60 * 60 * 24));
                var hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
                var minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
                var seconds = (mss % (1000 * 60)) / 1000;
                return days + " 天 " + hours + " 小时 " + minutes + " 分钟 " + seconds.toFixed() + " 秒 ";
            }
            async function getServerTime() {
                localStartTime = performance.now()
                return Promise.resolve(new Date("2023-06-02 12:00:00").getTime())
            }
            async function getServerEndTime() {
                return Promise.resolve(new Date("2023-06-02 12:01:00").getTime())
            }
            /**
             * @description: 开启定时器
             * @param {*} time // 毫秒数
             * @param {*} callback 没帧的回调,返回剩余毫秒数
             * @return {*} { stop,pause } 返回停止和暂停函数
             */
            function setTime(time, callback) {
                // 开启标志符
                var isProgressing = false
                // 本地结束时间
                let localEndTime = performance.now() + time
                function next() {
                    // 剩余的毫秒数
                    residueTime = localEndTime - performance.now()
                    residueTime = residueTime > 0 ? residueTime : 0
                    if (typeof callback == 'function') {
                        callback(residueTime)
                    }
                    if (residueTime > 0 && !isProgressing) {
                        requestAnimationFrame(next)
                    }
                }
                // 停止
                function stop() {
                    isProgressing = true
                    localEndTime = 0
                }
                // 暂停/开始
                function pause() {
                    isProgressing = !isProgressing
                    if (isProgressing === false && localEndTime != 0) {
                        // 重新开始重置本地结束时间
                        localEndTime = performance.now() + time
                        next()
                    } else {
                        // 获得剩余的时间
                        time = localEndTime - performance.now()
                    }
                }
                next()
                return {
                    stop,
                    pause
                }
            }
            async function start1() {
                var time = await getTime()
                let { stop, pause } = setTime(time, (residueTime) => {
                    let currentText = formatDuring(residueTime)
                    let dom = document.querySelector('.currentTime')
                    dom.innerHTML = currentText
                })
                let btn = document.querySelector('.stopBtn')
                btn.addEventListener('click', stop)
                let btn2 = document.querySelector('.pauseBtn')
                btn2.addEventListener('click', pause)
            }
            async function start2() {
                var time = await getTime()
                let { stop, pause } = setTime(time, (residueTime) => {
                    let currentText = formatDuring(residueTime > 0 ? residueTime : 0)
                    let dom = document.querySelector('.currentTime2')
                    dom.innerHTML = currentText
                })
                let btn = document.querySelector('.stopBtn2')
                btn.addEventListener('click', stop)
                let btn2 = document.querySelector('.pauseBtn2')
                btn2.addEventListener('click', pause)
            }
            start1()
            start2()
        })()
    </script>
</body>

</html>