JavaScript 前端倒計時糾偏實現

前端網頁倒計時是很是常見的應用,咱們在各大購物網站的秒殺活動中老是能見到它的身影。可是在實際狀況中,咱們經常會發現當網頁不刷新、讓倒計時程序持續運行時,顯示時間相比實際時間會愈來愈慢,相信你們也有在秒殺時間即將到來時不停刷新頁面的經歷。緣由天然也不難理解:倒計時一般使用定時器(setTimeout 或者 setInterval )實現,而 JavaScript 的單線程特性使得主線程執行棧中出現阻塞時,任務隊列中的異步任務並不能及時執行,所以瀏覽器並不能保證在定時器設置的時間結束後代碼老是被準時執行,這就形成了倒計時的誤差。javascript

通常的解決方法是前端定時向服務器發送請求獲取最新的時間差來校準倒計時時間,主動(程序裏設置定時請求)或被動的(F5 已被用戶按壞)區別而已。這個方法簡單但也有點粗暴,下面提供一種方法,可以必定程度上不依賴服務端實現倒計時的糾偏。代碼非原創,時間久遠忘了出處,在此記錄一下學習過程以避免遺忘。若有侵權請聯繫我。前端

首先咱們須要模擬主線程阻塞的環境,同時又不能讓主線程一直阻塞:java

setInterval(function(){ 
  let j = 0
  while(j++ < 100000000)
}, 0)

而後是主要的代碼:瀏覽器

const interval = 1000
let ms = 50000,  // 從服務器和活動開始時間計算出的時間差,這裏測試用 50000 ms
let count = 0
const startTime = new Date().getTime()
let timeCounter
if( ms >= 0) {
  timeCounter = setTimeout(countDownStart, interval)
}
 
function countDownStart () {
   count++
   const offset = new Date().getTime() - (startTime + count * interval) // A
   let nextTime = interval - offset
   if (nextTime < 0) { 
       nextTime = 0 
   }
   ms -= interval
   console.log(`偏差:${offset} ms,下一次執行:${nextTime} ms 後,離活動開始還有:${ms} ms`)
   if (ms < 0) {
     clearTimeout(timeCounter)
   } else {
     timeCounter = setTimeout(countDownStart, nextTime)
   }
 }

代碼的基本原理並不複雜:經過遞歸調用 setTimeout 進行倒計時操做的執行。而每次執行函數時會維護一個 count 變量,用以記錄已經執行過的倒計時次數,使用代碼 A 處的公式可計算出當前執行倒計時的時間與實際應執行時間的誤差,進而能夠計算出下次執行倒計時的時間。服務器

本文首發於個人博客(點此查看),歡迎關注。異步

相關文章
相關標籤/搜索