如何基于PHP与数据库实现全局同步的25秒循环倒计时?
全用户同步的25秒循环倒计时实现方案
一、数据库设计逻辑
不需要复杂表结构,仅需一张单条数据的表存储倒计时基准信息:
- 创建表
timer_sync:
CREATE TABLE timer_sync ( id INT PRIMARY KEY AUTO_INCREMENT, cycle_base_time TIMESTAMP NOT NULL COMMENT '当前循环的基准起始时间', cycle_interval INT NOT NULL DEFAULT 25 COMMENT '循环间隔(秒)' );
- 初始化数据:插入第一条基准记录,后续由服务器自动维护:
INSERT INTO timer_sync (cycle_base_time, cycle_interval) VALUES (NOW(), 25);
- 核心维护逻辑:服务器每次处理请求时,计算当前时间与
cycle_base_time的差值,若差值≥cycle_interval,则将cycle_base_time更新为最近的符合循环规则的时间点(即cycle_base_time + N*cycle_interval,N为整数),避免服务器时间波动导致的倒计时错位。
二、PHP后端实现(同步基准接口)
编写接口get_sync_timer.php,返回校准后的基准时间与循环间隔:
<?php // 替换为你的数据库连接信息 $conn = new mysqli('localhost', 'db_user', 'db_pwd', 'db_name'); if ($conn->connect_error) die("数据库连接失败: " . $conn->connect_error); // 查询当前基准数据 $result = $conn->query("SELECT cycle_base_time, cycle_interval FROM timer_sync WHERE id = 1"); $row = $result->fetch_assoc(); $baseTime = strtotime($row['cycle_base_time']); $interval = $row['cycle_interval']; // 计算当前时间与基准时间的差值 $currentTime = time(); $diff = $currentTime - $baseTime; // 若超出循环间隔,更新基准时间到最近的循环节点 if ($diff >= $interval) { $newBaseTime = $baseTime + ceil($diff / $interval) * $interval; $conn->query("UPDATE timer_sync SET cycle_base_time = FROM_UNIXTIME($newBaseTime) WHERE id = 1"); $baseTime = $newBaseTime; } // 返回JSON格式的同步信息 header('Content-Type: application/json'); echo json_encode([ 'base_time' => $baseTime, 'interval' => $interval ]); $conn->close(); ?>
三、前端JavaScript实现(同步倒计时)
替换原localStorage逻辑,改为从服务器拉取基准时间计算剩余时长:
let timerInterval = null; // 获取服务器同步的基准信息 async function getSyncTimerInfo() { try { const res = await fetch('get_sync_timer.php'); const data = await res.json(); return data; } catch (err) { console.error('同步信息获取失败:', err); // 异常降级:临时用本地时间替代(会导致不同步,仅作应急) return { base_time: Date.now() / 1000, interval: 25 }; } } // 格式化剩余时间为两位数秒数 function formatSeconds(remainingSeconds) { const seconds = Math.max(0, Math.floor(remainingSeconds)); return seconds < 10 ? `0${seconds}` : `${seconds}`; } // 启动同步倒计时 async function startSyncTimer() { const timerInfo = await getSyncTimerInfo(); const baseTimeMs = timerInfo.base_time * 1000; const intervalMs = timerInfo.interval * 1000; // 更新倒计时显示 function updateTimer() { const currentTimeMs = Date.now(); const elapsedMs = currentTimeMs - baseTimeMs; const remainingMs = intervalMs - (elapsedMs % intervalMs); const remainingSeconds = remainingMs / 1000; document.getElementById('timer').innerText = formatSeconds(remainingSeconds); } // 立即更新一次 updateTimer(); // 每100ms刷新一次(与原代码频率一致) timerInterval = setInterval(updateTimer, 100); } // 页面加载时启动倒计时 window.addEventListener('load', startSyncTimer); // 可选:页面隐藏时暂停计时,节省资源 document.addEventListener('visibilitychange', () => { if (document.hidden) { clearInterval(timerInterval); } else { startSyncTimer(); } });
四、关键注意事项
- 时间校准:所有计算基于服务器时间,避免用户本地时间偏差导致的不同步。
- 并发处理:高并发场景下,可给
UPDATE语句加行锁(UPDATE timer_sync ... FOR UPDATE),防止多请求同时修改基准时间。 - 异常兼容:前端需处理接口请求失败的情况,避免倒计时直接失效。
内容的提问来源于stack exchange,提问作者kennedyforf
相关产品推荐
相关产品推荐

