You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 03:25:13