
本文旨在解决基于 settimeout 实现的 javascript 秒表计时不准、逐渐变慢的问题。通过深入分析传统方法的缺陷,提出并详细演示了利用系统时间戳结合 requestanimationframe api 的解决方案,确保秒表计时的高度准确性和平滑的用户体验,并提供了完整的代码示例和实现解析。
在前端开发中,使用 JavaScript 实现一个毫秒级的秒表功能是常见的需求。然而,许多初学者在尝试时会遇到一个普遍的问题:秒表在运行时会逐渐变慢,与实际时间产生偏差,甚至出现几秒的累计误差。
原始的秒表实现通常依赖于 setTimeout 或 setInterval 函数,并尝试在每次回调中递增一个计数器,例如每10毫秒递增一次毫秒数。
// 原始实现片段
function stopwatch() {
if (timer) {
++count; // 毫秒计数
if (count > 99) { // 达到100毫秒,进位到秒
++sec;
count = 0;
}
// ... 其他进位逻辑
setTimeout(stopwatch, 10); // 10毫秒后再次调用
}
}这种方法存在两个主要问题:
为了解决上述计时误差问题,我们需要采取一种更可靠的策略:不再依赖于固定间隔递增计数器,而是基于系统时间来计算已经过去的总时长,并利用 requestAnimationFrame API 来优化更新频率。
立即学习“Java免费学习笔记(深入)”;
以下是采用新策略实现的 JavaScript 秒表代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Accurate Stopwatch</title>
<link rel="stylesheet" href="style.css" /> <!-- 假设有style.css文件 -->
</head>
<body>
<div id="container">
<div id="time">
<span class="digit" id="hr">00</span>
<span class="txt">Hr</span>
<span class="digit" id="min">00</span>
<span class="txt">Min</span>
<span class="digit" id="sec">00</span>
<span class="txt">Sec</span>
<span class="digit" id="count">00</span> <!-- 用于显示毫秒的十位数和个位数 -->
</div>
<div id="btn-container">
<button class="btn" id="Start" onclick="start()">Start</button>
<button class="btn" id="Stop" onclick="stop()">Stop</button>
<button class="btn" id="Reset" onclick="reset()">Reset</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>var hr = 0;
var min = 0;
var sec = 0;
var count = 0; // 这里的count将不再是累加的毫秒数,而是显示用的毫秒数
var Startbutton = document.getElementById("Start");
var timer = false; // 控制秒表运行状态
var start_time; // 记录秒表开始时的系统时间戳
var animationFrameId; // 用于存储 requestAnimationFrame 的ID,以便取消
/**
* 启动秒表计时
*/
function start() {
if (!timer) { // 防止重复点击
Startbutton.disabled = true;
timer = true;
start_time = (new Date()).getTime(); // 记录开始时间戳
stopwatch(); // 启动计时循环
}
}
/**
* 停止秒表计时
*/
function stop() {
timer = false;
start_time = null; // 清除起始时间
Startbutton.disabled = false;
if (animationFrameId) {
cancelAnimationFrame(animationFrameId); // 取消动画帧请求
}
}
/**
* 重置秒表
*/
function reset() {
stop(); // 先停止计时
hr = 0;
min = 0;
sec = 0;
count = 0;
// 更新显示为初始值
document.getElementById("hr").innerHTML = "00";
document.getElementById("min").innerHTML = "00";
document.getElementById("sec").innerHTML = "00";
document.getElementById("count").innerHTML = "00";
}
/**
* 秒表核心逻辑:计算并更新显示时间
*/
function stopwatch() {
if (timer) {
var now = (new Date()).getTime(); // 获取当前时间戳
var diff = now - start_time; // 计算从开始到现在的总毫秒数
// 使用 Date 对象和 toISOString() 方法将毫秒差值格式化为 HH:MM:SS.ms
// new Date(diff) 会创建一个表示从 UNIX 纪元开始经过 diff 毫秒的 Date 对象
// toISOString() 格式为 YYYY-MM-DDTHH:mm:ss.sssZ
// slice(11, 23) 截取 "HH:mm:ss.sss" 部分
var str_time = (new Date(diff).toISOString().slice(11, 23));
// 从格式化字符串中提取小时、分钟、秒和毫秒(前两位)
var hrString = str_time.substring(0, 2);
var minString = str_time.substring(3, 5);
var secString = str_time.substring(6, 8);
var countString = str_time.substring(9, 11); // 截取毫秒的前两位,即百分之一秒
// 更新DOM显示
document.getElementById("hr").innerHTML = hrString;
document.getElementById("min").innerHTML = minString;
document.getElementById("sec").innerHTML = secString;
document.getElementById("count").innerHTML = countString;
// 使用 requestAnimationFrame 调度下一次更新
// 确保更新与浏览器重绘同步,提供更流畅的体验
animationFrameId = requestAnimationFrame(stopwatch);
}
}通过将秒表的核心逻辑从基于递增计数器和不精确定时器的方式,转变为基于系统时间戳计算已逝时间并利用 requestAnimationFrame 进行高效、同步的显示更新,我们能够构建出一个高度准确且用户体验流畅的 JavaScript 秒表。这种方法不仅解决了传统方法中常见的计时误差问题,也遵循了现代前端动画和性能优化的最佳实践。理解并应用 Date 对象和 requestAnimationFrame 是实现精确前端计时和动画效果的关键。
以上就是JavaScript 精准秒表实现:告别计时误差与延迟的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号