JavaScript多秒表无法并行计时问题修复咨询
问题原因
多秒表无法并行计时的核心bug是所有秒表共用全局的time计时变量和running状态变量:
- 启动新秒表时会直接修改全局
running为1,覆盖其他运行中秒表的状态,导致旧秒表的递归计时逻辑被中断 - 全局
time变量只有一份,新秒表启动时会直接读取当前全局time的数值,自然会从其他秒表的累计时长开始计数 - 原有逻辑没有区分不同秒表的定时器,暂停操作会无差别终止所有秒表的计时循环
修复后完整代码
// 按秒表ID独立存储每个秒表的状态,互不干扰 const stopwatchMap = {}; // 新增秒表行渲染逻辑(修复重置按钮重复ID问题) var row_id = $('#hidden_row_id').val(); output = '<td>' + name + ' <input type="hidden" name="hidden_name[]" id="name' + row_id + '" class="name" value="' + name + '" /></td>'; output += '<td><span id="output' + row_id + '">00:00:00</span> <input type="hidden" name="hidden_time[]" id="time' + row_id + '" value=""/></td>'; output += '<td><button type="button" name="remove_details" class="btn remove_details" id="' + row_id + '"><i class="fa fa-times"></i></button></td>'; output += '<td><a class="btn" id ="startPause' + row_id + '" onClick="startPause(' + row_id + ')"><i class="fa fa-play"></i></a><a class="btn" id="reset'+row_id+'" onClick="reset(' + row_id + ')"><i class="fa fa-refresh"></i></a></td>'; $('#row_' + row_id + '').html(output); // 初始化当前新秒表的独立状态 stopwatchMap[row_id] = { time: 0, running: false, timer: null }; function startPause(i) { const current = stopwatchMap[i]; if (!current.running) { current.running = true; increment(i); document.getElementById(`startPause${i}`).innerHTML = "<i class='fa fa-pause'></i>"; } else { current.running = false; clearTimeout(current.timer); document.getElementById(`startPause${i}`).innerHTML = "<i class='fa fa-play'></i>"; } } function reset(i) { const current = stopwatchMap[i]; current.running = false; current.time = 0; clearTimeout(current.timer); document.getElementById(`startPause${i}`).innerHTML = "<i class='fa fa-play'></i>"; document.getElementById(`output${i}`).innerHTML = "00:00:00"; document.getElementById(`time${i}`).value = "00:00:00"; } function increment(i) { const current = stopwatchMap[i]; if (current.running) { current.timer = setTimeout(function() { current.time++; const mins = String(Math.floor(current.time / 10 / 60)).padStart(2, '0'); const secs = String(Math.floor(current.time / 10 % 60)).padStart(2, '0'); const tenths = current.time % 10; const timeStr = `${mins}:${secs}:0${tenths}`; document.getElementById(`output${i}`).innerHTML = timeStr; document.getElementById(`time${i}`).value = timeStr; increment(i); }, 100); } }
对应的HTML依赖:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
关键修改点
- 废弃全局共享的
time、running变量,用stopwatchMap按秒表唯一ID分别存储每个秒表的计时值、运行状态、定时器实例 - 暂停、重置操作只会清除当前操作秒表对应的定时器,不会影响其他正在运行的秒表
- 修复原代码中所有重置按钮ID重复的问题,避免DOM查询冲突
- 用
padStart简化了补零逻辑,代码更简洁
实现效果参考:
内容的提问来源于stack exchange,提问作者Md. Nahid Hasan Tamim
相关产品推荐
相关产品推荐

