xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

How to implement an accurate countdown timer with js

How to implement an accurate countdown timer with js

如何用 js 实现一个精确的倒计时器

原理剖析

  1. web worker

  2. js custom timer

  3. setTimeout / setInterval async bug (宏任务)


"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2020-07-0
 * @modified
 *
 * @description 使用 JavaScript 实现精确的 setTimeout 和 setInterval
 * @difficulty Easy Medium Hard
 * @complexity O(n)
 * @augments
 * @example
 * @link
 * @solutions
 *
 */

const log = console.log;

// 同步: 使用 js 实现精确的 setTimeout
function setTimeoutPreciseSimulator(callback, time = 0) {
  const begin = new Date().getTime();
  while (true) {
    const end = new Date().getTime();
    if(end - begin >= time) {
      log(`end - begin`, end - begin);
      callback();
      break;
    }
  }
}

// 同步: 使用 js 实现精确的 setInterval
function setIntervalPreciseSimulator(callback, time = 0, count = 10) {
  function interval(callback, time) {
    const begin = new Date().getTime();
    while (true) {
      const end = new Date().getTime();
      if(end - begin >= time) {
        log(`end - begin`, end - begin);
        callback();
        break;
      }
    }
    if(count) {
      log(`\ncount =`, count);
      count--;
      interval(callback, time);
    }
  }
  // init
  interval(callback, time);
}


solution

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2020-07-24
 * @modified
 *
 * @description 如何用 js 实现一个精确的倒计时器
 * @difficulty Easy Medium Hard
 * @complexity O(n)
 * @augments
 * @example
 * @link https://gaohaoyang.github.io/2016/11/25/how-to-write-a-count-down/
 * @solutions
 *
 */

const log = console.log;

// 同步: 使用 js 实现精确的 setTimeout
function setTimeoutPreciseSimulator(callback, time = 0) {
  const begin = new Date().getTime();
  while (true) {
    const end = new Date().getTime();
    if(end - begin >= time) {
      // log(`end - begin`, end - begin);
      callback();
      break;
    }
  }
}

// 同步: 使用 js 实现精确的 setInterval
function setIntervalPreciseSimulator(callback, time = 0) {
  function interval(callback, time) {
    const begin = new Date().getTime();
    while (true) {
      const end = new Date().getTime();
      if(end - begin >= time) {
        // log(`end - begin`, end - begin);
        callback();
        break;
      }
    }
    if(!hasFished) {
      interval(callback, time);
    }
  }
  // init
  interval(callback, time);
}

// 首次进入页面获取 server 的时间和 server 剩余的时间 / server 结束的时间
const autoCalculatorRemainTime = (serverTime, endTime) => {
  // const now = Date.parse(new Date());
  // const now = new Date().getTime();
  let total = endTime - serverTime;// ms
  while(total) {
    const seconds = Math.floor((total / 1000) % 60);
    const minutes = Math.floor((total / (1000 * 60)) % 60);
    const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
    const days = Math.floor(total / (1000 * 60 * 60 * 24));
    total -= 1000;
    setTimeoutPreciseSimulator(() => {
      log(`days hours minutes seconds =\n`, `${days}天-${hours}时-${minutes}分-${seconds}秒`);
    }, 1000);
    // log(`days hours minutes seconds =\n`, `${days}天-${hours}时-${minutes}分-${seconds}秒`);
  }
  log(`🎉 倒计时结束!`);
  // return {
  //   total,
  //   days,
  //   hours,
  //   minutes,
  //   seconds,
  // };
}

// DOM demo


new Date(`2020-07-30 11:00:00`).getTime();
// 1596078000000
new Date(`2020-07-30 11:00:01`).getTime();
// 1596078001000
// 3分钟后, 1s === 1000ms, 3 * 60 * 1000 === 180000ms
new Date(`2020-07-30 11:00:00`).getTime() + 3 * 60 * 1000;
// 1596078180000

const serverTime = new Date().getTime();
// 3分钟后
const endTime = new Date(serverTime + 3 * 60 * 1000).getTime();


autoCalculatorRemainTime(serverTime, endTime);


// let hasFished = false;
// setIntervalPreciseSimulator();



  1. new Date() 获取时间差,计算
/**
 * 获取剩余时间
 * @param  {Number} endTime      截止时间
 * @param  {Number} deviceTime 设备时间
 * @param  {Number} serverTime  服务端时间
 * @return {Object}                         剩余时间对象
 */
const getRemainTime = (endTime, deviceTime, serverTime) => {
    let t = endTime - Date.parse(new Date()) - serverTime + deviceTime;
    let seconds = Math.floor((t / 1000) % 60);
    let minutes = Math.floor((t / 1000 / 60) % 60);
    let hours = Math.floor((t / (1000 * 60 * 60)) % 24);
    let days = Math.floor(t / (1000 * 60 * 60 * 24));
    return {
        'total': t,
        'days': days,
        'hours': hours,
        'minutes': minutes,
        'seconds': seconds,
    };
}

demo

https://www.online-stopwatch.com/chinese/

https://www.online-stopwatch.com/chinese/full-screen-stopwatch.php

refs



©xgqfrms 2012-2020

www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!


posted @ 2020-07-24 23:23  xgqfrms  阅读(204)  评论(3编辑  收藏  举报