最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript如何實(shí)現(xiàn)精準(zhǔn)倒計(jì)時(shí)

 更新時(shí)間:2025年02月13日 08:50:54   作者:菜雞小謝  
這篇文章主要為大家詳細(xì)介紹了JavaScript如何實(shí)現(xiàn)精準(zhǔn)倒計(jì)時(shí)功能,文中的示例代碼簡(jiǎn)潔易懂,具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

為什么使用setTimeout、setInterval做倒計(jì)時(shí)不準(zhǔn)?

1、主要原因與JavaScript的執(zhí)行機(jī)制有關(guān)。JavaScript是單線程的,這意味著它一次只能執(zhí)行一個(gè)任務(wù)。當(dāng)你設(shè)置一個(gè)計(jì)時(shí)器時(shí),計(jì)時(shí)器的回調(diào)函數(shù)會(huì)被放入任務(wù)隊(duì)列中,等待事件循環(huán)來處理。然而,如果在計(jì)時(shí)器到期時(shí),調(diào)用棧中有其他任務(wù)正在執(zhí)行,計(jì)時(shí)器的回調(diào)函數(shù)就會(huì)被延遲執(zhí)行。這種延遲會(huì)導(dǎo)致計(jì)時(shí)器不準(zhǔn)確。

2、此外,瀏覽器對(duì) setTimeoutsetInterval 的最小時(shí)間間隔有一定的限制,通常在4毫秒或更高,這也會(huì)影響計(jì)時(shí)的精度。系統(tǒng)資源的限制,如CPU負(fù)載過高,也可能導(dǎo)致計(jì)時(shí)器的回調(diào)函數(shù)被延遲執(zhí)行。

知道了原因,問題就比較好解決了。

既然由于js是單線程機(jī)制,那我們就專門開一個(gè)線程來進(jìn)行倒計(jì)時(shí)不就行了,web worker 登場(chǎng)。

web worker 方案

import { ref } from 'vue'
?
let countDownWorker: Worker | null = null
export default function useCountDownWorker(defaultTime: number) {
  const seconds = ref(defaultTime)
  function initCountDownWorker() {
    if (!countDownWorker) {
      countDownWorker = new Worker(
        new URL('./count-down.work.js', import.meta.url),
        { type: 'module' }
      )
      countDownWorker.postMessage({ type: 'ready', data: defaultTime })
      countDownWorker.addEventListener('message', function (event) {
        const { type, data } = event.data
        switch (type) {
          case 'ready':
            console.log(data)
            break
          case 'data':
            seconds.value = data
            break
          case 'stop':
            break
          case 'end':
            countDownWorker?.terminate()
            countDownWorker = null
            break
          case 'reset':
            seconds.value = data
            break
        }
      })
      countDownWorker.addEventListener('error', function (event) {
        console.log(event)
      })
    }
  }
  function startCountDown() {
    if (!countDownWorker) {
      initCountDownWorker()
    }
    countDownWorker?.postMessage({ type: 'start' })
  }
  function stopCountDown() {
    countDownWorker?.postMessage({ type: 'stop' })
  }
  function resetCountDown() {
    countDownWorker?.postMessage({ type: 'reset', data: defaultTime })
  }
  return { seconds, startCountDown, stopCountDown, resetCountDown }
}

count-down.work.js

let seconds = 0
let interval = null
?
function countDown() {
  if (interval) {
    clearInterval(interval)
  }
  interval = setInterval(() => {
    if (seconds <= 0) {
      postMessage({ type: 'end' })
      return
    }
    seconds--
    postMessage({ type: 'data', data: seconds })
  }, 1000)
}
?
function stop() {
  clearInterval(interval)
  postMessage({ type: 'stop' })
}
?
function reset(data) {
  clearInterval(interval)
  seconds = data
  postMessage({ type: 'reset', data: seconds })
}
?
function ready() {
  postMessage({ type: 'ready', data: 'it is ready' })
}
?
addEventListener('message', function (event) {
  const { type, data } = event.data
  switch (type) {
    case 'ready':
      seconds = data
      ready()
      break
    case 'start':
      countDown()
      break
    case 'stop':
      stop()
      break
    case 'reset':
      reset(data)
      break
  }
})

requestAnimationFrame方案

除了單開一個(gè)線程外,還有另外一種方案,就是requestAnimationFrame方案,因?yàn)閞equestAnimationFrame對(duì)回調(diào)函數(shù)的調(diào)用頻率通常與顯示器的刷新率相匹配,最大限度地減少了阻塞和性能問題。具體實(shí)現(xiàn)如下

import { ref, type Ref } from 'vue'
let requestAnimationFrameId: number | null = null
export default function useCountDownRAF(defaultTime: number) {
  const seconds = ref(defaultTime)
  function countDown(seconds: Ref<number>) {
    const end = performance.now() + seconds.value * 1000
    const step = () => {
      const now = performance.now()
      const remaining = Math.max(0, end - now)
      seconds.value = Math.round(remaining / 1000)
      if (remaining > 0) {
        requestAnimationFrameId = requestAnimationFrame(step)
      } else {
        seconds.value = 0
        if (requestAnimationFrameId) {
          cancelAnimationFrame(requestAnimationFrameId)
          requestAnimationFrameId = null
        }
      }
    }
    requestAnimationFrame(step)
  }
  function startCountDown() {
    if (seconds.value <= 0) {
      seconds.value = defaultTime
    }
    countDown(seconds)
  }
  function stopCountDown() {
    if (requestAnimationFrameId) {
      cancelAnimationFrame(requestAnimationFrameId)
      requestAnimationFrameId = null
    }
  }
  function resetCountDown() {
    seconds.value = defaultTime
    stopCountDown()
  }
  return { seconds, startCountDown, stopCountDown, resetCountDown }
}

注意:使用requestAnimationFrame方案時(shí),當(dāng)頁面置于后臺(tái)時(shí),requestAnimationFrame回調(diào)會(huì)暫停執(zhí)行以節(jié)省性能,所以需要依托performance.now()(這個(gè)更好,Date會(huì)存在系統(tǒng)時(shí)間被篡改的風(fēng)險(xiǎn))或者Date.now()來修正倒計(jì)時(shí)時(shí)間。

到此這篇關(guān)于JavaScript如何實(shí)現(xiàn)精準(zhǔn)倒計(jì)時(shí)的文章就介紹到這了,更多相關(guān)JavaScript倒計(jì)時(shí)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

峨边| 越西县| 萨嘎县| 清水河县| 衡阳市| 弥渡县| 卫辉市| 唐山市| 枞阳县| 二手房| 上栗县| 新疆| 卓资县| 肥城市| 九龙坡区| 安泽县| 仙游县| 保靖县| 丹阳市| 凌海市| 岱山县| 上饶县| 安庆市| 桐梓县| 九台市| 白玉县| 门源| 连云港市| 长子县| 茂名市| 上林县| 青铜峡市| 鄂州市| 三河市| 班玛县| 五峰| 邵阳县| 资溪县| 常州市| 大宁县| 常山县|