基于Cookie的JS倒计时页面刷新后时间回跳问题排查
刷新页面后倒计时数值偏大问题修复
问题根因
所有问题均来自时间计算的单位错误和逻辑设计缺陷:
- 剩余时长计算单位不匹配
原代码计算初始剩余时间的逻辑为:var timing = 60 * (60 * 24 -(Date.now() - getCookie('timer')) / 3600 / 24)Date.now()和Cookie中存储的值都是毫秒级时间戳,原代码做差值后没有先除以1000转换为秒,直接除以3600、24做时间换算,得到的数值远大于实际剩余秒数,这就是刷新后时间偏大的核心原因。 - 重置逻辑阈值错误
原代码判断时间差超过60*24天(1440天)才重置Cookie,但Cookie本身设置的max-age只有1天,该判断完全不生效。 - 计时逻辑存在固有缺陷
原逻辑在页面加载时记录start时间点,后续仅基于该时间点计算本次打开页面后的流逝时间,setInterval本身的触发延迟会逐步累积误差;倒计时归零时仅修改start变量,没有同步更新Cookie,会导致后续刷新后计时完全错乱。
修复后完整代码
注:保留了原代码中适配SO代码片段的cookieStore兼容逻辑,生产环境可按需移除
// 总倒计时时长:1天,单位秒 const TOTAL_DURATION = 24 * 60 * 60; const COOKIE_MAX_AGE = 24 * 60 * 60; function startTimer(display) { function timer() { const timerCookie = getCookie('timer'); // 直接基于Cookie存储的初始时间戳计算剩余值,避免setInterval累积误差 const elapsedSecond = Math.floor((Date.now() - Number(timerCookie)) / 1000); let diff = TOTAL_DURATION - elapsedSecond; // 倒计时归零,重置Cookie if (diff <= 0) { setCookie('timer', Date.now()); diff = TOTAL_DURATION; } const hours = String(Math.floor((diff / 3600) % 24)).padStart(2, '0'); const minutes = String(Math.floor((diff / 60) % 60)).padStart(2, '0'); const seconds = String(diff % 60).padStart(2, '0'); display.textContent = `${hours}:${minutes}:${seconds}`; } timer(); setInterval(timer, 1000); } window.cookieStore ||= {}; function getCookie(name) { try { const match = document.cookie.match(RegExp('(?:^|;\\s*)' + name + '=([^;]*)')); return match ? match[1] : null; } catch (err) { return window.cookieStore[name]; } } function setCookie(name, value) { try { document.cookie = `${name}=${value}; max-age=${COOKIE_MAX_AGE}`; } catch (err) { window.cookieStore[name] = value; } } // 初始化Cookie:不存在或已过期时重置 const savedTimer = getCookie('timer'); if (!savedTimer || (Date.now() - Number(savedTimer))/1000 >= TOTAL_DURATION) { setCookie('timer', Date.now()); } window.onload = function () { const display = document.querySelector('#time'); startTimer(display); };
对应HTML代码:
<div id="time"></div>
修复说明
- 统一所有时间计算的单位:时间戳差值先除以1000转换为秒后再做后续运算,从根源解决数值偏大问题
- 去掉
startTimer中依赖页面加载时间点的start变量,每次执行计时函数时直接读取Cookie中的初始时间戳计算剩余值,完全避免setInterval触发延迟带来的累积误差,也不需要在页面加载时提前计算剩余时长 - 修正重置逻辑:剩余时长归零时直接更新Cookie中的初始时间戳,重置判断阈值和Cookie过期时间保持一致,均为1天
- 用
padStart简化补零逻辑,代码可读性更高
内容的提问来源于stack exchange,提问作者zeflex
相关产品推荐
相关产品推荐

