C语言1000秒倒计时的代码,写个秒杀倒计时方法

背景

项目里有个秒杀倒计时功能模块。

1460000024550914

页面切换Tab后,一段时间再回来发现明显慢了。撸代码吧:// ...

CountDown.prototype.count = function() {

var self = this;

this.clear();

this.timeout = setTimeout(function(){

// 计数减1

if(--self.currCount <= 0) {

// ...

} else {

// ...

self.count();

}

}, this.options.step)

}

内部通过setTimeout实现的,并且通过计数方式记录剩余时间。

问题分析页面切换Tab后,再回来发现明显慢了。

这个是浏览器的Timer throttling策略

用“次数”表示时间是不准确的。

setTimeout(fn, delay),并不是表示delay时间后一定执行fn,而是表示 最早delay 后执行fn。所以用次数表示时间是不准确。

解决方案方案2:用户切回浏览器TAB时更正倒计时。

不使用“计数方式”计算时间,通过计算setTimeout(fn, delay)中fn函数两次执行间隔来计算剩余时间。

综合考虑下最终采用【方案2】解决问题。

方案实施getTimerParts.js剩余时间格式化方法const units = ['ms', 's', 'm', 'h', 'd'];

const divider = [1, 1000, 1000 * 60, 1000 * 60 * 60, 1000 * 60 * 60 * 24];

const unitMod = [1000, 60, 60, 24];

/**

* 返回值格式:

* {

* d: xxx,

* h: xxx,

* m: xxx,

* s: xxx,

* ms: xxx

* }

*/

export default function getTimerParts(time, lastUnit = 'd') {

const lastUnitIndex = units.indexOf(lastUnit);

const timerParts = units.reduce((timerParts, unit, index) => {

timerParts[unit] = index > lastUnitIndex

? 0

: index === lastUnitIndex

? Math.floor(time / divider[index])

: Math.floor(time / divider[index]) % unitMod[index];

return timerParts;

}, {});

return timerParts;

}countDown.js 倒计时构造函数import getTimerParts from './getTimerParts'

function now() {

return window.performance

? window.performance.now()

: Date.now();

}

export default function CountDown({ initialTime, step, onChange, onStart }) {

this.initialTime = initialTime || 0;

this.time = this.initialTime;

this.currentInternalTime = now();

this.step = step || 1000;

this.onChange = onChange || (() => {});

this.onStart = onStart || (() => {});

}

CountDown.prototype.start = function() {

this.stop();

this.onStart(getTimerParts(this.time));

// 记录首次执行时间

this.currentInternalTime = now();

this.loop();

}

CountDown.prototype.loop = function() {

// 开启倒计时

this.timer = setTimeout(() => {

// 通过执行时间差计算剩余时间

const currentInternalTime = now();

const delta = currentInternalTime - this.currentInternalTime;

this.time = this.time - delta;

if(this.time < 0) {

this.time = 0;

}

// 记录本次执行的时间点

this.currentInternalTime = currentInternalTime;

this.onChange(getTimerParts(this.time));

if(this.time === 0 ) {

this.stop();

} else {

this.loop();

}

}, this.step);

}

CountDown.prototype.stop = function() {

if(this.timer) {

clearTimeout(this.timer);

}

}

简单的引用方:import CountDown from '../../src/lib/timer'

import { useEffect, useState } from 'react'

export default function TimerPage() {

const [timeParts, setTimeParts] = useState(null)

useEffect(() => {

const countDown = new CountDown({

initialTime: 10000,

onStart: setTimeParts,

onChange: setTimeParts

});

countDown.start();

}, [])

return (

{

timeParts && `${timeParts.d}天 ${timeParts.h}:${timeParts.m}:${timeParts.s}`

}

)

}

遗留问题:setTimer(fn, delay)两次执行fn时间间隔大于delay的,如果执行间隔比较大的话会会造成倒计时跳级。

参考

整理自gitHub 笔记: 如何写个倒计时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值