js定時(shí)器不準(zhǔn)確問(wèn)題的解決方法
為什么會(huì)出現(xiàn)定時(shí)器不準(zhǔn)確呢?
這個(gè)其實(shí)就得提到j(luò)s執(zhí)行機(jī)制了,叫做事件循環(huán)Eventloop 循環(huán)機(jī)制中,異步事件 setInterval 到時(shí)后會(huì)把回調(diào)函數(shù)放入消息隊(duì)列中Event Queue,主線程的宏任務(wù)執(zhí)行完畢后依次執(zhí)行消息隊(duì)列的微任務(wù),等微任務(wù)執(zhí)行完了在循環(huán)回來(lái)執(zhí)行宏任務(wù)。并且由于消息隊(duì)列中存在大量任務(wù),其他任務(wù)執(zhí)行時(shí)間就會(huì)造成定時(shí)器回調(diào)函數(shù)的延遲,如果不處理則會(huì)一直疊加延遲。
以下是ChatGPT給出的的一些解決JS定時(shí)器不準(zhǔn)確問(wèn)題的方法:
使用精度更高的定時(shí)器:使用requestAnimationFrame()代替setInterval或setTimeout,因?yàn)樗猿R?guī)更新率刷新屏幕,并保證在用戶可見(jiàn)的時(shí)間內(nèi)繪制動(dòng)畫(huà)。requestAnimationFrame()是基于瀏覽器屏幕的重繪機(jī)制觸發(fā)的,可以有效避免誤差的累積。
縮短定時(shí)間隔時(shí)間:如果一個(gè)定時(shí)器在瀏覽器里表現(xiàn)得很不準(zhǔn)確,可能需要縮小時(shí)間間隔,比如說(shuō)從100毫秒改成10毫秒。
使用標(biāo)準(zhǔn)時(shí)間: 可以使用標(biāo)準(zhǔn)時(shí)間對(duì)象提供的函數(shù)(如getTime、getSeconds等)獲取當(dāng)前時(shí)間,而不是使用JavaScript自帶的全局變量Date來(lái)保證計(jì)時(shí)器的準(zhǔn)確性。
避免多個(gè)計(jì)時(shí)器同時(shí)存在:如果多個(gè)計(jì)時(shí)器同時(shí)存在,可能會(huì)導(dǎo)致其他定時(shí)器的執(zhí)行被延遲或丟失調(diào)用。只使用唯一一個(gè)計(jì)時(shí)器進(jìn)行安排和管理。
總之,實(shí)際場(chǎng)景中,可結(jié)合具體應(yīng)用場(chǎng)景選擇相符的解決方案。
我們開(kāi)發(fā)過(guò)程中也可以通過(guò)計(jì)算時(shí)差可以有效的解決。
接下來(lái)是我自己整理的方法
通過(guò)動(dòng)態(tài)計(jì)算時(shí)差解決setInterval定時(shí)器不準(zhǔn)確的問(wèn)題
根據(jù)定時(shí)器最開(kāi)始時(shí)間計(jì)算當(dāng)前時(shí)間(回調(diào)函數(shù)執(zhí)行時(shí)間)與開(kāi)始時(shí)間的誤差,用期望時(shí)差減誤差作為下一次任務(wù)的時(shí)間間隔
在開(kāi)始執(zhí)行計(jì)時(shí)器之前,記錄本地時(shí)間。
在計(jì)時(shí)器函數(shù)中,獲取當(dāng)前本地時(shí)間,并計(jì)算與記錄的本地時(shí)間之間的時(shí)差(單位為毫秒)。
在計(jì)算得到的時(shí)差的基礎(chǔ)上,添加上期望的時(shí)間間隔,便是下一次計(jì)時(shí)器應(yīng)該觸發(fā)的時(shí)間。
在定時(shí)器回調(diào)函數(shù)中,采用setTimeout代替setInterval,并傳入計(jì)算得到的時(shí)間差作為等待時(shí)間。
let localTime = new Date().getTime(); //記錄本地時(shí)間 function timer() { const now = new Date().getTime(); // 獲取當(dāng)前本地時(shí)間 const timeGap = now - localTime; // 計(jì)算時(shí)間差 // 下一次計(jì)時(shí)器應(yīng)該觸發(fā)的時(shí)間 const nextTickTime = 1000 - (timeGap % 1000); setTimeout(() => { // 在此處執(zhí)行計(jì)時(shí)器的操作 console.log('tick'); timer(); // 遞歸調(diào)用,實(shí)現(xiàn)循環(huán) }, nextTickTime); } timer(); // 啟動(dòng)計(jì)時(shí)器
這種方法能夠避免JavaScript在處理大量任務(wù)時(shí)的卡頓和延遲,保證定時(shí)器的調(diào)用的準(zhǔn)確性。
使用 web Worker解決setInterval定時(shí)器不準(zhǔn)確的問(wèn)題
原理:將定時(shí)函數(shù)作為獨(dú)立線程執(zhí)行
Web Worker 是運(yùn)行在后臺(tái)線程中的 JavaScript 腳本,可以與主線程并行工作,因此不會(huì)受主線程的影響。我們可以使用 Web Worker 來(lái)創(chuàng)建一個(gè)新的線程來(lái)處理定時(shí)器。
以下是一個(gè)簡(jiǎn)單的示例:
//在 main.js 中創(chuàng)建 Worker const worker = new Worker("worker.js"); //在 worker.js 中處理定時(shí)器 let intervalId = null; worker.onmessage = function(event) { console.log("Received message from main script"); if (event.data === "start") { intervalId = setInterval(function() { console.log("Worker: Interval fired"); postMessage("tick"); }, 1000); } else if (event.data === "stop") { clearInterval(intervalId); intervalId = null; } };
在主線程中,我們首先創(chuàng)建一個(gè)新的 Web Worker worker.js,然后通過(guò)調(diào)用 onmessage 方法來(lái)監(jiān)聽(tīng)來(lái)自 Worker 的消息。當(dāng)收到 start 消息時(shí),我們?cè)?Worker 中啟動(dòng)一個(gè)定時(shí)器。當(dāng)收到 stop 消息時(shí),我們清除定時(shí)器。
以下是 worker.js 文件的內(nèi)容:
//worker.js onmessage = function(event) { console.log("Received message from main script"); if (event.data === "start") { console.log("Worker: Starting interval"); intervalId = setInterval(function() { console.log("Worker: Interval fired"); postMessage("tick"); }, 1000); } else if (event.data === "stop") { console.log("Worker: Stopping interval"); clearInterval(intervalId); intervalId = null; } };
在 Worker 中,我們定義了一個(gè) onmessage 方法來(lái)監(jiān)聽(tīng)來(lái)自主線程的消息。當(dāng)收到 start 消息時(shí),我們?cè)?Worker 中啟動(dòng)一個(gè)定時(shí)器;當(dāng)收到 stop 消息時(shí),我們清除定時(shí)器。通過(guò)調(diào)用 postMessage 方法來(lái)將消息發(fā)送回主線程。
現(xiàn)在,可以通過(guò)向 Worker 發(fā)送 start 和 stop 消息來(lái)控制定時(shí)器的啟動(dòng)和停止。由于該定時(shí)器是在 Worker 線程中運(yùn)行的,因此它不會(huì)受到主線程的影響,從而保證了定時(shí)器的準(zhǔn)確性。
到此這篇關(guān)于js定時(shí)器不準(zhǔn)確問(wèn)題的解決方法的文章就介紹到這了,更多相關(guān)js定時(shí)器不準(zhǔn)確內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在使用JSON格式處理數(shù)據(jù)時(shí)應(yīng)該注意的問(wèn)題小結(jié)
這篇文章主要介紹了在使用JSON格式處理數(shù)據(jù)時(shí)應(yīng)該注意的問(wèn)題,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-05-05Bootstrap打造一個(gè)左側(cè)折疊菜單的系統(tǒng)模板(一)
這篇文章主要介紹了Bootstrap打造一個(gè)左側(cè)折疊菜單的系統(tǒng)模板(一)的相關(guān)資料,需要的朋友可以參考下2016-05-05微信小程序官方動(dòng)態(tài)自定義底部tabBar的例子
這篇文章主要介紹了微信小程序官方動(dòng)態(tài)自定義底部tabBar的例子,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09JavaScript this關(guān)鍵字指向常用情況解析
這篇文章主要介紹了JavaScript this關(guān)鍵字指向常用情況解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09js replace 與replaceall實(shí)例用法詳解
這篇文章介紹了js replace 與replaceall實(shí)例用法詳解,有需要的朋友可以參考一下2013-08-08js實(shí)現(xiàn)懸浮窗效果(支持拖動(dòng))
本文主要介紹了js實(shí)現(xiàn)懸浮窗效果(支持拖動(dòng))的實(shí)例,具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-03-03Javascript ES6中數(shù)據(jù)類型Symbol的使用詳解
Symbol類型是es6新增的一個(gè)數(shù)據(jù)類型,Symbol值通過(guò)Symbol函數(shù)生成Symbol類型是保證每個(gè)屬性的名字都是獨(dú)一無(wú)二的,對(duì)于一個(gè)對(duì)象由對(duì)個(gè)模塊構(gòu)成的情況非常有用,本文主要介紹了Javascript ES6中數(shù)據(jù)類型Symbol使用的相關(guān)資料,需要的朋友可以參考下。2017-05-05