【每日一題】倒計時實現(xiàn)如何解決時間偏差?

人生苦短,總需要一點儀式感。比如學(xué)前端~
setTimeout/setInterval 實現(xiàn)倒計時如何解決時間偏差?
造成時間誤差的原因
在前端實現(xiàn)中一般會通過 setTimeout 和 setInterval 方法實現(xiàn)一個倒計時效果。但是使用這些方法會存在時間偏差的問題,這是由于 js 的程序執(zhí)行機制造成的。setTimeout 和 setInterval 的作用是隔一段時間將回調(diào)事件加入到事件隊列中,由于JS的事件循環(huán)機制限制,加入到事件隊列中的回調(diào)函數(shù)并不是立即執(zhí)行的,它會等到當前執(zhí)行棧為空的時候再被取出并執(zhí)行。因此,事件函數(shù)等待執(zhí)行的時間就是造成定時器時間誤差的原因。
解決倒計時中的誤差有兩種辦法:
-
第一種就是通過前端定時向服務(wù)器發(fā)送請求獲取最新的時間差,以此來校準倒計時時間。但是這樣會存在一個很大的問題,就是每隔一秒去請求服務(wù)器,這樣如果用戶多了,服務(wù)器就會奔潰---內(nèi)存占用率很大 -
第二種方式是前端根據(jù)偏差時間來自動調(diào)整間隔時間的方式來實現(xiàn)的。這一方式首先是以 setTimeout 遞歸的方式來實現(xiàn)倒計時,然后通過一個變量來記錄已經(jīng)倒計時的秒數(shù)。每一次函數(shù)調(diào)用的時候,每次都將變量+1,然后根據(jù)這個變量和每次的間隔時間,我們就可以計算出此時無偏差時應(yīng)該顯示的時間。然后將當前的真實時間與這個時間相減,這樣我們就可以得到時間的偏差大小,因此我們在設(shè)置下一個定時器的間隔大小的時候,我們就從間隔時間中減去這個偏差大小,以此來糾正由于程序執(zhí)行所造成的時間誤差。
const interval = 1000;
// 從服務(wù)器和活動開始時間計算出的時間差,這里測試用 50000 ms
let ms = 50000;
let count = 0; //記錄次數(shù)
const startTime = new Date().getTime(); //開始時間
let timeCounter;
if (ms >= 0) {
timerCounter = setTimeout(countDownStart, interval); //返回一個對象
}
function countDownStart() {
count++;
const offset = new Date().getTime() - (startTime + count * interval); //剩余的時間
let nextInterval = interval - offset;
if (nextInterval < 0) {
nextInterval = 0;
}
ms -= interval;
console.log(
`誤差:${offset} ms,下一次執(zhí)行:${nextInterval} ms 后,離活動開始還有:${ms} ms`
);
if (ms < 0) {
clearTimeout(timeCounter); //銷毀定時器
} else {
timeCounter = setTimeout(countDownStart, nextInterval); //重開一個定時器
}
}
執(zhí)行結(jié)果圖

代碼圖解

讓我們一起攜手同走前端路!
關(guān)注公眾號回復(fù)【加群】即可
評論
圖片
表情
