摘要:前端網(wǎng)頁倒計(jì)時(shí)是非常常見的應(yīng)用,我們?cè)诟鞔筚徫锞W(wǎng)站的秒殺活動(dòng)中總是能見到它的身影。這個(gè)方法簡(jiǎn)單但也有點(diǎn)粗暴,下面提供一種方法,能夠一定程度上不依賴服務(wù)端實(shí)現(xiàn)倒計(jì)時(shí)的糾偏。
前端網(wǎng)頁倒計(jì)時(shí)是非常常見的應(yīng)用,我們?cè)诟鞔筚徫锞W(wǎng)站的秒殺活動(dòng)中總是能見到它的身影。但是在實(shí)際情況中,我們常常會(huì)發(fā)現(xiàn)當(dāng)網(wǎng)頁不刷新、讓倒計(jì)時(shí)程序持續(xù)運(yùn)行時(shí),顯示時(shí)間相比實(shí)際時(shí)間會(huì)越來越慢,相信大家也有在秒殺時(shí)間即將到來時(shí)不停刷新頁面的經(jīng)歷。原因自然也不難理解:倒計(jì)時(shí)通常使用定時(shí)器(setTimeout 或者 setInterval )實(shí)現(xiàn),而 JavaScript 的單線程特性使得主線程執(zhí)行棧中出現(xiàn)阻塞時(shí),任務(wù)隊(duì)列中的異步任務(wù)并不能及時(shí)執(zhí)行,因此瀏覽器并不能保證在定時(shí)器設(shè)置的時(shí)間結(jié)束后代碼總是被準(zhǔn)時(shí)執(zhí)行,這就造成了倒計(jì)時(shí)的偏差。
一般的解決方法是前端定時(shí)向服務(wù)器發(fā)送請(qǐng)求獲取最新的時(shí)間差來校準(zhǔn)倒計(jì)時(shí)時(shí)間,主動(dòng)(程序里設(shè)置定時(shí)請(qǐng)求)或被動(dòng)的(F5 已被用戶按壞)區(qū)別而已。這個(gè)方法簡(jiǎn)單但也有點(diǎn)粗暴,下面提供一種方法,能夠一定程度上不依賴服務(wù)端實(shí)現(xiàn)倒計(jì)時(shí)的糾偏。代碼非原創(chuàng),時(shí)間久遠(yuǎn)忘了出處,在此記錄一下學(xué)習(xí)過程以免遺忘。如有侵權(quán)請(qǐng)聯(lián)系我。
首先我們需要模擬主線程阻塞的環(huán)境,同時(shí)又不能讓主線程一直阻塞:
setInterval(function(){ let j = 0 while(j++ < 100000000) }, 0)
然后是主要的代碼:
const interval = 1000 let ms = 50000, // 從服務(wù)器和活動(dòng)開始時(shí)間計(jì)算出的時(shí)間差,這里測(cè)試用 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,下一次執(zhí)行:${nextTime} ms 后,離活動(dòng)開始還有:${ms} ms`) if (ms < 0) { clearTimeout(timeCounter) } else { timeCounter = setTimeout(countDownStart, nextTime) } }
代碼的基本原理并不復(fù)雜:通過遞歸調(diào)用 setTimeout 進(jìn)行倒計(jì)時(shí)操作的執(zhí)行。而每次執(zhí)行函數(shù)時(shí)會(huì)維護(hù)一個(gè) count 變量,用以記錄已經(jīng)執(zhí)行過的倒計(jì)時(shí)次數(shù),使用代碼 A 處的公式可計(jì)算出當(dāng)前執(zhí)行倒計(jì)時(shí)的時(shí)間與實(shí)際應(yīng)執(zhí)行時(shí)間的偏差,進(jìn)而可以計(jì)算出下次執(zhí)行倒計(jì)時(shí)的時(shí)間。
本文首發(fā)于我的博客(點(diǎn)此查看),歡迎關(guān)注。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98042.html
摘要:由于引擎同一時(shí)間只執(zhí)行一段代碼這是由單線程的性質(zhì)決定的,所以每個(gè)代碼塊阻塞了其它異步事件的進(jìn)行。這意味著瀏覽器將等待著一個(gè)新的異步事件發(fā)生。異步的任務(wù)執(zhí)行的順序是不固定的,主要看返回的速度。 我們經(jīng)常說JS是單線程的,比如node.js研討會(huì)上大家都說JS的特色之一是單線程的,這樣使JS更簡(jiǎn)單明了,可是大家真的理解所謂JS的單線程機(jī)制嗎?單線程時(shí),基于事件的異步機(jī)制又該當(dāng)如何,這些知識(shí)...
摘要:注意客戶端與服務(wù)器日期進(jìn)行傳輸?shù)臅r(shí)候一般都是用大整數(shù)時(shí)間戳進(jìn)行傳輸。 前言 一個(gè)網(wǎng)站的開發(fā)需要要UI、前端、后端三種工程師?,F(xiàn)在的企業(yè)在招聘前端工程師的時(shí)候一般都要求其了解或者掌握一些后端的知識(shí)。因此,此文章主要介紹javascript的日期類型,也粗略的介紹一下php的日期類型,以及二者是如何交互數(shù)據(jù)的。 時(shí)間戳 什么是時(shí)間戳 時(shí)間戳是從格林威治時(shí)間1970年1月1日(00:0...
摘要:注意客戶端與服務(wù)器日期進(jìn)行傳輸?shù)臅r(shí)候一般都是用大整數(shù)時(shí)間戳進(jìn)行傳輸。 前言 一個(gè)網(wǎng)站的開發(fā)需要要UI、前端、后端三種工程師。現(xiàn)在的企業(yè)在招聘前端工程師的時(shí)候一般都要求其了解或者掌握一些后端的知識(shí)。因此,此文章主要介紹javascript的日期類型,也粗略的介紹一下php的日期類型,以及二者是如何交互數(shù)據(jù)的。 時(shí)間戳 什么是時(shí)間戳 時(shí)間戳是從格林威治時(shí)間1970年1月1日(00:0...
摘要:案例每隔毫秒調(diào)用函數(shù)并顯示時(shí)間。當(dāng)點(diǎn)擊按鈕時(shí),停止時(shí)間代碼如下計(jì)時(shí)器每隔毫秒調(diào)用函數(shù),并將返回值賦值給計(jì)時(shí)器計(jì)時(shí)器,在載入后延遲指定時(shí)間后去執(zhí)行一次表達(dá)式僅執(zhí)行一次。該值標(biāo)識(shí)要取消的延遲執(zhí)行代碼塊。 簡(jiǎn)述 本系列將持續(xù)更新Javascript基礎(chǔ)部分的知識(shí),誰都想掌握高端大氣的技術(shù),但是我覺得沒有一個(gè)扎實(shí)的基礎(chǔ),我認(rèn)為一切高階技術(shù)對(duì)我來講都是過眼云煙,要成為一名及格的前端工程師,必須把...
摘要:網(wǎng)上有很多前端的學(xué)習(xí)路徑文章,大多是知識(shí)點(diǎn)羅列為主或是資料的匯總,數(shù)據(jù)量讓新人望而卻步。天了解一個(gè)前端框架。也可以關(guān)注微信公眾號(hào)曉舟報(bào)告,發(fā)送獲取資料,就能收到下載密碼,網(wǎng)盤地址在最下方,獲取教程和案例的資料。 前言 好的學(xué)習(xí)方法可以事半功倍,好的學(xué)習(xí)路徑可以指明前進(jìn)方向。這篇文章不僅要寫學(xué)習(xí)路徑,還要寫學(xué)習(xí)方法,還要發(fā)資料,干貨滿滿,準(zhǔn)備接招。 網(wǎng)上有很多前端的學(xué)習(xí)路徑文章,大多是知...
閱讀 3371·2021-11-11 16:54
閱讀 3526·2021-10-11 10:58
閱讀 1265·2021-08-30 09:41
閱讀 1809·2019-08-30 15:54
閱讀 2036·2019-08-30 14:00
閱讀 2710·2019-08-29 17:13
閱讀 1678·2019-08-29 15:19
閱讀 614·2019-08-29 15:14