如何在Node.js中使用JSON文件存储倒计时剩余实时时长?
解决服务器重启后倒计时不重置的方案
核心思路
只存储初始时长无法恢复重启前的剩余进度,必须记录倒计时的截止时间戳。服务器重启后,通过当前时间与截止时间的差值计算剩余时长,就能还原之前的倒计时状态。
具体实现步骤
1. 修改存储文件结构
将原StartTime.json改为记录每个用户的初始时长(秒)和截止时间戳(毫秒),示例:
{ "UserTime": [ { "id": 1, "name": "Jack", "initialDuration": 1500, // 25分钟转秒:25*60=1500 "deadline": 1720000000000 // 倒计时结束的毫秒时间戳 }, { "id": 2, "name": "Mike", "initialDuration": 1800, // 30分钟转秒:30*60=1800 "deadline": 1720001000000 } ] }
注意:把时分格式的时长转成秒数,用Date.now()生成毫秒级时间戳,方便后续计算。
2. 服务器启动时恢复倒计时
读取存储的截止时间,计算当前剩余时长:
const fs = require('fs').promises; async function loadUserTimers() { const data = await fs.readFile('./StartTime.json', 'utf8'); const userTime = JSON.parse(data).UserTime; return userTime.map(user => { const now = Date.now(); // 计算剩余秒数,确保不出现负数 let remainingSeconds = Math.max(0, (user.deadline - now) / 1000); // 可选逻辑:如果倒计时已结束,自动重置为初始时长并更新截止时间 if (remainingSeconds === 0) { remainingSeconds = user.initialDuration; user.deadline = now + remainingSeconds * 1000; await saveUserTimers(userTime); } return { ...user, remainingSeconds }; }); } async function saveUserTimers(userTime) { await fs.writeFile('./StartTime.json', JSON.stringify({ UserTime: userTime }, null, 2)); }
3. 实时更新并持久化状态
不要每秒写入文件(影响性能),建议在计时器状态变化(开始/暂停/结束)或定时(比如每分钟)更新截止时间:
async function updateUserDeadline(userId, newDeadline) { const data = await fs.readFile('./StartTime.json', 'utf8'); const userTime = JSON.parse(data).UserTime; const userIndex = userTime.findIndex(u => u.id === userId); if (userIndex !== -1) { userTime[userIndex].deadline = newDeadline; await saveUserTimers(userTime); } } // 示例:每分钟批量更新一次文件 setInterval(async () => { // 这里可根据实际逻辑,更新正在运行的计时器截止时间 }, 60000);
4. 初始化新计时器逻辑
当用户首次创建计时器时,计算截止时间并写入文件:
async function createUserTimer(userId, name, initialMinutes) { const initialDuration = initialMinutes * 60; const deadline = Date.now() + initialDuration * 1000; const data = await fs.readFile('./StartTime.json', 'utf8'); const userTime = JSON.parse(data).UserTime; userTime.push({ id: userId, name, initialDuration, deadline }); await saveUserTimers(userTime); }
额外注意事项
- 错误处理:文件读写操作需包裹
try/catch,避免程序因文件操作失败崩溃。 - 时间精度:始终用毫秒级时间戳计算,不要依赖字符串格式的时间,避免解析误差。
- 并发安全:如果有多个进程操作文件,建议用文件锁或改用轻量数据库(如SQLite)替代JSON文件,避免数据冲突。
内容的提问来源于stack exchange,提问作者maranR
相关产品推荐
相关产品推荐

